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/parser/create.js b/node_modules/css-tree/lib/parser/create.js
new file mode 100644
index 0000000..a01f625
--- /dev/null
+++ b/node_modules/css-tree/lib/parser/create.js
@@ -0,0 +1,304 @@
+var OffsetToLocation = require('../common/OffsetToLocation');
+var SyntaxError = require('../common/SyntaxError');
+var TokenStream = require('../common/TokenStream');
+var List = require('../common/List');
+var tokenize = require('../tokenizer');
+var constants = require('../tokenizer/const');
+var { findWhiteSpaceStart, cmpStr } = require('../tokenizer/utils');
+var sequence = require('./sequence');
+var noop = function() {};
+
+var TYPE = constants.TYPE;
+var NAME = constants.NAME;
+var WHITESPACE = TYPE.WhiteSpace;
+var COMMENT = TYPE.Comment;
+var IDENT = TYPE.Ident;
+var FUNCTION = TYPE.Function;
+var URL = TYPE.Url;
+var HASH = TYPE.Hash;
+var PERCENTAGE = TYPE.Percentage;
+var NUMBER = TYPE.Number;
+var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
+var NULL = 0;
+
+function createParseContext(name) {
+ return function() {
+ return this[name]();
+ };
+}
+
+function processConfig(config) {
+ var parserConfig = {
+ context: {},
+ scope: {},
+ atrule: {},
+ pseudo: {}
+ };
+
+ if (config.parseContext) {
+ for (var name in config.parseContext) {
+ switch (typeof config.parseContext[name]) {
+ case 'function':
+ parserConfig.context[name] = config.parseContext[name];
+ break;
+
+ case 'string':
+ parserConfig.context[name] = createParseContext(config.parseContext[name]);
+ break;
+ }
+ }
+ }
+
+ if (config.scope) {
+ for (var name in config.scope) {
+ parserConfig.scope[name] = config.scope[name];
+ }
+ }
+
+ if (config.atrule) {
+ for (var name in config.atrule) {
+ var atrule = config.atrule[name];
+
+ if (atrule.parse) {
+ parserConfig.atrule[name] = atrule.parse;
+ }
+ }
+ }
+
+ if (config.pseudo) {
+ for (var name in config.pseudo) {
+ var pseudo = config.pseudo[name];
+
+ if (pseudo.parse) {
+ parserConfig.pseudo[name] = pseudo.parse;
+ }
+ }
+ }
+
+ if (config.node) {
+ for (var name in config.node) {
+ parserConfig[name] = config.node[name].parse;
+ }
+ }
+
+ return parserConfig;
+}
+
+module.exports = function createParser(config) {
+ var parser = {
+ scanner: new TokenStream(),
+ locationMap: new OffsetToLocation(),
+
+ filename: '<unknown>',
+ needPositions: false,
+ onParseError: noop,
+ onParseErrorThrow: false,
+ parseAtrulePrelude: true,
+ parseRulePrelude: true,
+ parseValue: true,
+ parseCustomProperty: false,
+
+ readSequence: sequence,
+
+ createList: function() {
+ return new List();
+ },
+ createSingleNodeList: function(node) {
+ return new List().appendData(node);
+ },
+ getFirstListNode: function(list) {
+ return list && list.first();
+ },
+ getLastListNode: function(list) {
+ return list.last();
+ },
+
+ parseWithFallback: function(consumer, fallback) {
+ var startToken = this.scanner.tokenIndex;
+
+ try {
+ return consumer.call(this);
+ } catch (e) {
+ if (this.onParseErrorThrow) {
+ throw e;
+ }
+
+ var fallbackNode = fallback.call(this, startToken);
+
+ this.onParseErrorThrow = true;
+ this.onParseError(e, fallbackNode);
+ this.onParseErrorThrow = false;
+
+ return fallbackNode;
+ }
+ },
+
+ lookupNonWSType: function(offset) {
+ do {
+ var type = this.scanner.lookupType(offset++);
+ if (type !== WHITESPACE) {
+ return type;
+ }
+ } while (type !== NULL);
+
+ return NULL;
+ },
+
+ eat: function(tokenType) {
+ if (this.scanner.tokenType !== tokenType) {
+ var offset = this.scanner.tokenStart;
+ var message = NAME[tokenType] + ' is expected';
+
+ // tweak message and offset
+ switch (tokenType) {
+ case IDENT:
+ // when identifier is expected but there is a function or url
+ if (this.scanner.tokenType === FUNCTION || this.scanner.tokenType === URL) {
+ offset = this.scanner.tokenEnd - 1;
+ message = 'Identifier is expected but function found';
+ } else {
+ message = 'Identifier is expected';
+ }
+ break;
+
+ case HASH:
+ if (this.scanner.isDelim(NUMBERSIGN)) {
+ this.scanner.next();
+ offset++;
+ message = 'Name is expected';
+ }
+ break;
+
+ case PERCENTAGE:
+ if (this.scanner.tokenType === NUMBER) {
+ offset = this.scanner.tokenEnd;
+ message = 'Percent sign is expected';
+ }
+ break;
+
+ default:
+ // when test type is part of another token show error for current position + 1
+ // e.g. eat(HYPHENMINUS) will fail on "-foo", but pointing on "-" is odd
+ if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === tokenType) {
+ offset = offset + 1;
+ }
+ }
+
+ this.error(message, offset);
+ }
+
+ this.scanner.next();
+ },
+
+ consume: function(tokenType) {
+ var value = this.scanner.getTokenValue();
+
+ this.eat(tokenType);
+
+ return value;
+ },
+ consumeFunctionName: function() {
+ var name = this.scanner.source.substring(this.scanner.tokenStart, this.scanner.tokenEnd - 1);
+
+ this.eat(FUNCTION);
+
+ return name;
+ },
+
+ getLocation: function(start, end) {
+ if (this.needPositions) {
+ return this.locationMap.getLocationRange(
+ start,
+ end,
+ this.filename
+ );
+ }
+
+ return null;
+ },
+ getLocationFromList: function(list) {
+ if (this.needPositions) {
+ var head = this.getFirstListNode(list);
+ var tail = this.getLastListNode(list);
+ return this.locationMap.getLocationRange(
+ head !== null ? head.loc.start.offset - this.locationMap.startOffset : this.scanner.tokenStart,
+ tail !== null ? tail.loc.end.offset - this.locationMap.startOffset : this.scanner.tokenStart,
+ this.filename
+ );
+ }
+
+ return null;
+ },
+
+ error: function(message, offset) {
+ var location = typeof offset !== 'undefined' && offset < this.scanner.source.length
+ ? this.locationMap.getLocation(offset)
+ : this.scanner.eof
+ ? this.locationMap.getLocation(findWhiteSpaceStart(this.scanner.source, this.scanner.source.length - 1))
+ : this.locationMap.getLocation(this.scanner.tokenStart);
+
+ throw new SyntaxError(
+ message || 'Unexpected input',
+ this.scanner.source,
+ location.offset,
+ location.line,
+ location.column
+ );
+ }
+ };
+
+ config = processConfig(config || {});
+ for (var key in config) {
+ parser[key] = config[key];
+ }
+
+ return function(source, options) {
+ options = options || {};
+
+ var context = options.context || 'default';
+ var onComment = options.onComment;
+ var ast;
+
+ tokenize(source, parser.scanner);
+ parser.locationMap.setSource(
+ source,
+ options.offset,
+ options.line,
+ options.column
+ );
+
+ parser.filename = options.filename || '<unknown>';
+ parser.needPositions = Boolean(options.positions);
+ parser.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop;
+ parser.onParseErrorThrow = false;
+ parser.parseAtrulePrelude = 'parseAtrulePrelude' in options ? Boolean(options.parseAtrulePrelude) : true;
+ parser.parseRulePrelude = 'parseRulePrelude' in options ? Boolean(options.parseRulePrelude) : true;
+ parser.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true;
+ parser.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false;
+
+ if (!parser.context.hasOwnProperty(context)) {
+ throw new Error('Unknown context `' + context + '`');
+ }
+
+ if (typeof onComment === 'function') {
+ parser.scanner.forEachToken((type, start, end) => {
+ if (type === COMMENT) {
+ const loc = parser.getLocation(start, end);
+ const value = cmpStr(source, end - 2, end, '*/')
+ ? source.slice(start + 2, end - 2)
+ : source.slice(start + 2, end);
+
+ onComment(value, loc);
+ }
+ });
+ }
+
+ ast = parser.context[context].call(parser, options);
+
+ if (!parser.scanner.eof) {
+ parser.error();
+ }
+
+ return ast;
+ };
+};