Add packages to optimize svgs dynamically

These packages will be used to dynamically optimize SVG images
during the build.

R=jacktfranklin@chromium.org

Bug: 1216402
Change-Id: I04e95aa7d79c9d67beaf8a7861182c52b16b7d0f
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2939992
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
diff --git a/node_modules/css-tree/lib/common/List.js b/node_modules/css-tree/lib/common/List.js
new file mode 100644
index 0000000..5da834a
--- /dev/null
+++ b/node_modules/css-tree/lib/common/List.js
@@ -0,0 +1,576 @@
+//
+//                              list
+//                            ┌──────┐
+//             ┌──────────────┼─head │
+//             │              │ tail─┼──────────────┐
+//             │              └──────┘              │
+//             ▼                                    ▼
+//            item        item        item        item
+//          ┌──────┐    ┌──────┐    ┌──────┐    ┌──────┐
+//  null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │
+//          │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null
+//          ├──────┤    ├──────┤    ├──────┤    ├──────┤
+//          │ data │    │ data │    │ data │    │ data │
+//          └──────┘    └──────┘    └──────┘    └──────┘
+//
+
+function createItem(data) {
+    return {
+        prev: null,
+        next: null,
+        data: data
+    };
+}
+
+function allocateCursor(node, prev, next) {
+    var cursor;
+
+    if (cursors !== null) {
+        cursor = cursors;
+        cursors = cursors.cursor;
+        cursor.prev = prev;
+        cursor.next = next;
+        cursor.cursor = node.cursor;
+    } else {
+        cursor = {
+            prev: prev,
+            next: next,
+            cursor: node.cursor
+        };
+    }
+
+    node.cursor = cursor;
+
+    return cursor;
+}
+
+function releaseCursor(node) {
+    var cursor = node.cursor;
+
+    node.cursor = cursor.cursor;
+    cursor.prev = null;
+    cursor.next = null;
+    cursor.cursor = cursors;
+    cursors = cursor;
+}
+
+var cursors = null;
+var List = function() {
+    this.cursor = null;
+    this.head = null;
+    this.tail = null;
+};
+
+List.createItem = createItem;
+List.prototype.createItem = createItem;
+
+List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) {
+    var cursor = this.cursor;
+
+    while (cursor !== null) {
+        if (cursor.prev === prevOld) {
+            cursor.prev = prevNew;
+        }
+
+        if (cursor.next === nextOld) {
+            cursor.next = nextNew;
+        }
+
+        cursor = cursor.cursor;
+    }
+};
+
+List.prototype.getSize = function() {
+    var size = 0;
+    var cursor = this.head;
+
+    while (cursor) {
+        size++;
+        cursor = cursor.next;
+    }
+
+    return size;
+};
+
+List.prototype.fromArray = function(array) {
+    var cursor = null;
+
+    this.head = null;
+
+    for (var i = 0; i < array.length; i++) {
+        var item = createItem(array[i]);
+
+        if (cursor !== null) {
+            cursor.next = item;
+        } else {
+            this.head = item;
+        }
+
+        item.prev = cursor;
+        cursor = item;
+    }
+
+    this.tail = cursor;
+
+    return this;
+};
+
+List.prototype.toArray = function() {
+    var cursor = this.head;
+    var result = [];
+
+    while (cursor) {
+        result.push(cursor.data);
+        cursor = cursor.next;
+    }
+
+    return result;
+};
+
+List.prototype.toJSON = List.prototype.toArray;
+
+List.prototype.isEmpty = function() {
+    return this.head === null;
+};
+
+List.prototype.first = function() {
+    return this.head && this.head.data;
+};
+
+List.prototype.last = function() {
+    return this.tail && this.tail.data;
+};
+
+List.prototype.each = function(fn, context) {
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, null, this.head);
+
+    while (cursor.next !== null) {
+        item = cursor.next;
+        cursor.next = item.next;
+
+        fn.call(context, item.data, item, this);
+    }
+
+    // pop cursor
+    releaseCursor(this);
+};
+
+List.prototype.forEach = List.prototype.each;
+
+List.prototype.eachRight = function(fn, context) {
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, this.tail, null);
+
+    while (cursor.prev !== null) {
+        item = cursor.prev;
+        cursor.prev = item.prev;
+
+        fn.call(context, item.data, item, this);
+    }
+
+    // pop cursor
+    releaseCursor(this);
+};
+
+List.prototype.forEachRight = List.prototype.eachRight;
+
+List.prototype.reduce = function(fn, initialValue, context) {
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, null, this.head);
+    var acc = initialValue;
+
+    while (cursor.next !== null) {
+        item = cursor.next;
+        cursor.next = item.next;
+
+        acc = fn.call(context, acc, item.data, item, this);
+    }
+
+    // pop cursor
+    releaseCursor(this);
+
+    return acc;
+};
+
+List.prototype.reduceRight = function(fn, initialValue, context) {
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, this.tail, null);
+    var acc = initialValue;
+
+    while (cursor.prev !== null) {
+        item = cursor.prev;
+        cursor.prev = item.prev;
+
+        acc = fn.call(context, acc, item.data, item, this);
+    }
+
+    // pop cursor
+    releaseCursor(this);
+
+    return acc;
+};
+
+List.prototype.nextUntil = function(start, fn, context) {
+    if (start === null) {
+        return;
+    }
+
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, null, start);
+
+    while (cursor.next !== null) {
+        item = cursor.next;
+        cursor.next = item.next;
+
+        if (fn.call(context, item.data, item, this)) {
+            break;
+        }
+    }
+
+    // pop cursor
+    releaseCursor(this);
+};
+
+List.prototype.prevUntil = function(start, fn, context) {
+    if (start === null) {
+        return;
+    }
+
+    var item;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    // push cursor
+    var cursor = allocateCursor(this, start, null);
+
+    while (cursor.prev !== null) {
+        item = cursor.prev;
+        cursor.prev = item.prev;
+
+        if (fn.call(context, item.data, item, this)) {
+            break;
+        }
+    }
+
+    // pop cursor
+    releaseCursor(this);
+};
+
+List.prototype.some = function(fn, context) {
+    var cursor = this.head;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    while (cursor !== null) {
+        if (fn.call(context, cursor.data, cursor, this)) {
+            return true;
+        }
+
+        cursor = cursor.next;
+    }
+
+    return false;
+};
+
+List.prototype.map = function(fn, context) {
+    var result = new List();
+    var cursor = this.head;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    while (cursor !== null) {
+        result.appendData(fn.call(context, cursor.data, cursor, this));
+        cursor = cursor.next;
+    }
+
+    return result;
+};
+
+List.prototype.filter = function(fn, context) {
+    var result = new List();
+    var cursor = this.head;
+
+    if (context === undefined) {
+        context = this;
+    }
+
+    while (cursor !== null) {
+        if (fn.call(context, cursor.data, cursor, this)) {
+            result.appendData(cursor.data);
+        }
+        cursor = cursor.next;
+    }
+
+    return result;
+};
+
+List.prototype.clear = function() {
+    this.head = null;
+    this.tail = null;
+};
+
+List.prototype.copy = function() {
+    var result = new List();
+    var cursor = this.head;
+
+    while (cursor !== null) {
+        result.insert(createItem(cursor.data));
+        cursor = cursor.next;
+    }
+
+    return result;
+};
+
+List.prototype.prepend = function(item) {
+    //      head
+    //    ^
+    // item
+    this.updateCursors(null, item, this.head, item);
+
+    // insert to the beginning of the list
+    if (this.head !== null) {
+        // new item <- first item
+        this.head.prev = item;
+
+        // new item -> first item
+        item.next = this.head;
+    } else {
+        // if list has no head, then it also has no tail
+        // in this case tail points to the new item
+        this.tail = item;
+    }
+
+    // head always points to new item
+    this.head = item;
+
+    return this;
+};
+
+List.prototype.prependData = function(data) {
+    return this.prepend(createItem(data));
+};
+
+List.prototype.append = function(item) {
+    return this.insert(item);
+};
+
+List.prototype.appendData = function(data) {
+    return this.insert(createItem(data));
+};
+
+List.prototype.insert = function(item, before) {
+    if (before !== undefined && before !== null) {
+        // prev   before
+        //      ^
+        //     item
+        this.updateCursors(before.prev, item, before, item);
+
+        if (before.prev === null) {
+            // insert to the beginning of list
+            if (this.head !== before) {
+                throw new Error('before doesn\'t belong to list');
+            }
+
+            // since head points to before therefore list doesn't empty
+            // no need to check tail
+            this.head = item;
+            before.prev = item;
+            item.next = before;
+
+            this.updateCursors(null, item);
+        } else {
+
+            // insert between two items
+            before.prev.next = item;
+            item.prev = before.prev;
+
+            before.prev = item;
+            item.next = before;
+        }
+    } else {
+        // tail
+        //      ^
+        //      item
+        this.updateCursors(this.tail, item, null, item);
+
+        // insert to the ending of the list
+        if (this.tail !== null) {
+            // last item -> new item
+            this.tail.next = item;
+
+            // last item <- new item
+            item.prev = this.tail;
+        } else {
+            // if list has no tail, then it also has no head
+            // in this case head points to new item
+            this.head = item;
+        }
+
+        // tail always points to new item
+        this.tail = item;
+    }
+
+    return this;
+};
+
+List.prototype.insertData = function(data, before) {
+    return this.insert(createItem(data), before);
+};
+
+List.prototype.remove = function(item) {
+    //      item
+    //       ^
+    // prev     next
+    this.updateCursors(item, item.prev, item, item.next);
+
+    if (item.prev !== null) {
+        item.prev.next = item.next;
+    } else {
+        if (this.head !== item) {
+            throw new Error('item doesn\'t belong to list');
+        }
+
+        this.head = item.next;
+    }
+
+    if (item.next !== null) {
+        item.next.prev = item.prev;
+    } else {
+        if (this.tail !== item) {
+            throw new Error('item doesn\'t belong to list');
+        }
+
+        this.tail = item.prev;
+    }
+
+    item.prev = null;
+    item.next = null;
+
+    return item;
+};
+
+List.prototype.push = function(data) {
+    this.insert(createItem(data));
+};
+
+List.prototype.pop = function() {
+    if (this.tail !== null) {
+        return this.remove(this.tail);
+    }
+};
+
+List.prototype.unshift = function(data) {
+    this.prepend(createItem(data));
+};
+
+List.prototype.shift = function() {
+    if (this.head !== null) {
+        return this.remove(this.head);
+    }
+};
+
+List.prototype.prependList = function(list) {
+    return this.insertList(list, this.head);
+};
+
+List.prototype.appendList = function(list) {
+    return this.insertList(list);
+};
+
+List.prototype.insertList = function(list, before) {
+    // ignore empty lists
+    if (list.head === null) {
+        return this;
+    }
+
+    if (before !== undefined && before !== null) {
+        this.updateCursors(before.prev, list.tail, before, list.head);
+
+        // insert in the middle of dist list
+        if (before.prev !== null) {
+            // before.prev <-> list.head
+            before.prev.next = list.head;
+            list.head.prev = before.prev;
+        } else {
+            this.head = list.head;
+        }
+
+        before.prev = list.tail;
+        list.tail.next = before;
+    } else {
+        this.updateCursors(this.tail, list.tail, null, list.head);
+
+        // insert to end of the list
+        if (this.tail !== null) {
+            // if destination list has a tail, then it also has a head,
+            // but head doesn't change
+
+            // dest tail -> source head
+            this.tail.next = list.head;
+
+            // dest tail <- source head
+            list.head.prev = this.tail;
+        } else {
+            // if list has no a tail, then it also has no a head
+            // in this case points head to new item
+            this.head = list.head;
+        }
+
+        // tail always start point to new item
+        this.tail = list.tail;
+    }
+
+    list.head = null;
+    list.tail = null;
+
+    return this;
+};
+
+List.prototype.replace = function(oldItem, newItemOrList) {
+    if ('head' in newItemOrList) {
+        this.insertList(newItemOrList, oldItem);
+    } else {
+        this.insert(newItemOrList, oldItem);
+    }
+
+    this.remove(oldItem);
+};
+
+module.exports = List;
diff --git a/node_modules/css-tree/lib/common/OffsetToLocation.js b/node_modules/css-tree/lib/common/OffsetToLocation.js
new file mode 100644
index 0000000..eee8228
--- /dev/null
+++ b/node_modules/css-tree/lib/common/OffsetToLocation.js
@@ -0,0 +1,91 @@
+var adoptBuffer = require('./adopt-buffer');
+var isBOM = require('../tokenizer').isBOM;
+
+var N = 10;
+var F = 12;
+var R = 13;
+
+function computeLinesAndColumns(host, source) {
+    var sourceLength = source.length;
+    var lines = adoptBuffer(host.lines, sourceLength); // +1
+    var line = host.startLine;
+    var columns = adoptBuffer(host.columns, sourceLength);
+    var column = host.startColumn;
+    var startOffset = source.length > 0 ? isBOM(source.charCodeAt(0)) : 0;
+
+    for (var i = startOffset; i < sourceLength; i++) { // -1
+        var code = source.charCodeAt(i);
+
+        lines[i] = line;
+        columns[i] = column++;
+
+        if (code === N || code === R || code === F) {
+            if (code === R && i + 1 < sourceLength && source.charCodeAt(i + 1) === N) {
+                i++;
+                lines[i] = line;
+                columns[i] = column;
+            }
+
+            line++;
+            column = 1;
+        }
+    }
+
+    lines[i] = line;
+    columns[i] = column;
+
+    host.lines = lines;
+    host.columns = columns;
+}
+
+var OffsetToLocation = function() {
+    this.lines = null;
+    this.columns = null;
+    this.linesAndColumnsComputed = false;
+};
+
+OffsetToLocation.prototype = {
+    setSource: function(source, startOffset, startLine, startColumn) {
+        this.source = source;
+        this.startOffset = typeof startOffset === 'undefined' ? 0 : startOffset;
+        this.startLine = typeof startLine === 'undefined' ? 1 : startLine;
+        this.startColumn = typeof startColumn === 'undefined' ? 1 : startColumn;
+        this.linesAndColumnsComputed = false;
+    },
+
+    ensureLinesAndColumnsComputed: function() {
+        if (!this.linesAndColumnsComputed) {
+            computeLinesAndColumns(this, this.source);
+            this.linesAndColumnsComputed = true;
+        }
+    },
+    getLocation: function(offset, filename) {
+        this.ensureLinesAndColumnsComputed();
+
+        return {
+            source: filename,
+            offset: this.startOffset + offset,
+            line: this.lines[offset],
+            column: this.columns[offset]
+        };
+    },
+    getLocationRange: function(start, end, filename) {
+        this.ensureLinesAndColumnsComputed();
+
+        return {
+            source: filename,
+            start: {
+                offset: this.startOffset + start,
+                line: this.lines[start],
+                column: this.columns[start]
+            },
+            end: {
+                offset: this.startOffset + end,
+                line: this.lines[end],
+                column: this.columns[end]
+            }
+        };
+    }
+};
+
+module.exports = OffsetToLocation;
diff --git a/node_modules/css-tree/lib/common/SyntaxError.js b/node_modules/css-tree/lib/common/SyntaxError.js
new file mode 100644
index 0000000..0cbf16a
--- /dev/null
+++ b/node_modules/css-tree/lib/common/SyntaxError.js
@@ -0,0 +1,82 @@
+var createCustomError = require('../utils/createCustomError');
+var MAX_LINE_LENGTH = 100;
+var OFFSET_CORRECTION = 60;
+var TAB_REPLACEMENT = '    ';
+
+function sourceFragment(error, extraLines) {
+    function processLines(start, end) {
+        return lines.slice(start, end).map(function(line, idx) {
+            var num = String(start + idx + 1);
+
+            while (num.length < maxNumLength) {
+                num = ' ' + num;
+            }
+
+            return num + ' |' + line;
+        }).join('\n');
+    }
+
+    var lines = error.source.split(/\r\n?|\n|\f/);
+    var line = error.line;
+    var column = error.column;
+    var startLine = Math.max(1, line - extraLines) - 1;
+    var endLine = Math.min(line + extraLines, lines.length + 1);
+    var maxNumLength = Math.max(4, String(endLine).length) + 1;
+    var cutLeft = 0;
+
+    // column correction according to replaced tab before column
+    column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length;
+
+    if (column > MAX_LINE_LENGTH) {
+        cutLeft = column - OFFSET_CORRECTION + 3;
+        column = OFFSET_CORRECTION - 2;
+    }
+
+    for (var i = startLine; i <= endLine; i++) {
+        if (i >= 0 && i < lines.length) {
+            lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT);
+            lines[i] =
+                (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') +
+                lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) +
+                (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : '');
+        }
+    }
+
+    return [
+        processLines(startLine, line),
+        new Array(column + maxNumLength + 2).join('-') + '^',
+        processLines(line, endLine)
+    ].filter(Boolean).join('\n');
+}
+
+var SyntaxError = function(message, source, offset, line, column) {
+    var error = createCustomError('SyntaxError', message);
+
+    error.source = source;
+    error.offset = offset;
+    error.line = line;
+    error.column = column;
+
+    error.sourceFragment = function(extraLines) {
+        return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines);
+    };
+    Object.defineProperty(error, 'formattedMessage', {
+        get: function() {
+            return (
+                'Parse error: ' + error.message + '\n' +
+                sourceFragment(error, 2)
+            );
+        }
+    });
+
+    // for backward capability
+    error.parseError = {
+        offset: offset,
+        line: line,
+        column: column
+    };
+
+    return error;
+};
+
+module.exports = SyntaxError;
diff --git a/node_modules/css-tree/lib/common/TokenStream.js b/node_modules/css-tree/lib/common/TokenStream.js
new file mode 100644
index 0000000..c41ed1b
--- /dev/null
+++ b/node_modules/css-tree/lib/common/TokenStream.js
@@ -0,0 +1,219 @@
+var constants = require('../tokenizer/const');
+var TYPE = constants.TYPE;
+var NAME = constants.NAME;
+
+var utils = require('../tokenizer/utils');
+var cmpStr = utils.cmpStr;
+
+var EOF = TYPE.EOF;
+var WHITESPACE = TYPE.WhiteSpace;
+var COMMENT = TYPE.Comment;
+
+var OFFSET_MASK = 0x00FFFFFF;
+var TYPE_SHIFT = 24;
+
+var TokenStream = function() {
+    this.offsetAndType = null;
+    this.balance = null;
+
+    this.reset();
+};
+
+TokenStream.prototype = {
+    reset: function() {
+        this.eof = false;
+        this.tokenIndex = -1;
+        this.tokenType = 0;
+        this.tokenStart = this.firstCharOffset;
+        this.tokenEnd = this.firstCharOffset;
+    },
+
+    lookupType: function(offset) {
+        offset += this.tokenIndex;
+
+        if (offset < this.tokenCount) {
+            return this.offsetAndType[offset] >> TYPE_SHIFT;
+        }
+
+        return EOF;
+    },
+    lookupOffset: function(offset) {
+        offset += this.tokenIndex;
+
+        if (offset < this.tokenCount) {
+            return this.offsetAndType[offset - 1] & OFFSET_MASK;
+        }
+
+        return this.source.length;
+    },
+    lookupValue: function(offset, referenceStr) {
+        offset += this.tokenIndex;
+
+        if (offset < this.tokenCount) {
+            return cmpStr(
+                this.source,
+                this.offsetAndType[offset - 1] & OFFSET_MASK,
+                this.offsetAndType[offset] & OFFSET_MASK,
+                referenceStr
+            );
+        }
+
+        return false;
+    },
+    getTokenStart: function(tokenIndex) {
+        if (tokenIndex === this.tokenIndex) {
+            return this.tokenStart;
+        }
+
+        if (tokenIndex > 0) {
+            return tokenIndex < this.tokenCount
+                ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK
+                : this.offsetAndType[this.tokenCount] & OFFSET_MASK;
+        }
+
+        return this.firstCharOffset;
+    },
+
+    // TODO: -> skipUntilBalanced
+    getRawLength: function(startToken, mode) {
+        var cursor = startToken;
+        var balanceEnd;
+        var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK;
+        var type;
+
+        loop:
+        for (; cursor < this.tokenCount; cursor++) {
+            balanceEnd = this.balance[cursor];
+
+            // stop scanning on balance edge that points to offset before start token
+            if (balanceEnd < startToken) {
+                break loop;
+            }
+
+            type = this.offsetAndType[cursor] >> TYPE_SHIFT;
+
+            // check token is stop type
+            switch (mode(type, this.source, offset)) {
+                case 1:
+                    break loop;
+
+                case 2:
+                    cursor++;
+                    break loop;
+
+                default:
+                    // fast forward to the end of balanced block
+                    if (this.balance[balanceEnd] === cursor) {
+                        cursor = balanceEnd;
+                    }
+
+                    offset = this.offsetAndType[cursor] & OFFSET_MASK;
+            }
+        }
+
+        return cursor - this.tokenIndex;
+    },
+    isBalanceEdge: function(pos) {
+        return this.balance[this.tokenIndex] < pos;
+    },
+    isDelim: function(code, offset) {
+        if (offset) {
+            return (
+                this.lookupType(offset) === TYPE.Delim &&
+                this.source.charCodeAt(this.lookupOffset(offset)) === code
+            );
+        }
+
+        return (
+            this.tokenType === TYPE.Delim &&
+            this.source.charCodeAt(this.tokenStart) === code
+        );
+    },
+
+    getTokenValue: function() {
+        return this.source.substring(this.tokenStart, this.tokenEnd);
+    },
+    getTokenLength: function() {
+        return this.tokenEnd - this.tokenStart;
+    },
+    substrToCursor: function(start) {
+        return this.source.substring(start, this.tokenStart);
+    },
+
+    skipWS: function() {
+        for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) {
+            if ((this.offsetAndType[i] >> TYPE_SHIFT) !== WHITESPACE) {
+                break;
+            }
+        }
+
+        if (skipTokenCount > 0) {
+            this.skip(skipTokenCount);
+        }
+    },
+    skipSC: function() {
+        while (this.tokenType === WHITESPACE || this.tokenType === COMMENT) {
+            this.next();
+        }
+    },
+    skip: function(tokenCount) {
+        var next = this.tokenIndex + tokenCount;
+
+        if (next < this.tokenCount) {
+            this.tokenIndex = next;
+            this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK;
+            next = this.offsetAndType[next];
+            this.tokenType = next >> TYPE_SHIFT;
+            this.tokenEnd = next & OFFSET_MASK;
+        } else {
+            this.tokenIndex = this.tokenCount;
+            this.next();
+        }
+    },
+    next: function() {
+        var next = this.tokenIndex + 1;
+
+        if (next < this.tokenCount) {
+            this.tokenIndex = next;
+            this.tokenStart = this.tokenEnd;
+            next = this.offsetAndType[next];
+            this.tokenType = next >> TYPE_SHIFT;
+            this.tokenEnd = next & OFFSET_MASK;
+        } else {
+            this.tokenIndex = this.tokenCount;
+            this.eof = true;
+            this.tokenType = EOF;
+            this.tokenStart = this.tokenEnd = this.source.length;
+        }
+    },
+
+    forEachToken(fn) {
+        for (var i = 0, offset = this.firstCharOffset; i < this.tokenCount; i++) {
+            var start = offset;
+            var item = this.offsetAndType[i];
+            var end = item & OFFSET_MASK;
+            var type = item >> TYPE_SHIFT;
+
+            offset = end;
+
+            fn(type, start, end, i);
+        }
+    },
+
+    dump() {
+        var tokens = new Array(this.tokenCount);
+
+        this.forEachToken((type, start, end, index) => {
+            tokens[index] = {
+                idx: index,
+                type: NAME[type],
+                chunk: this.source.substring(start, end),
+                balance: this.balance[index]
+            };
+        });
+
+        return tokens;
+    }
+};
+
+module.exports = TokenStream;
diff --git a/node_modules/css-tree/lib/common/adopt-buffer.js b/node_modules/css-tree/lib/common/adopt-buffer.js
new file mode 100644
index 0000000..ef35b9b
--- /dev/null
+++ b/node_modules/css-tree/lib/common/adopt-buffer.js
@@ -0,0 +1,10 @@
+var MIN_SIZE = 16 * 1024;
+var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported
+
+module.exports = function adoptBuffer(buffer, size) {
+    if (buffer === null || buffer.length < size) {
+        return new SafeUint32Array(Math.max(size + 1024, MIN_SIZE));
+    }
+
+    return buffer;
+};