//------------------------------------------------------------------------------
const esquery = require("esquery");
-const lodash = require("lodash");
//------------------------------------------------------------------------------
// Typedefs
// Helpers
//------------------------------------------------------------------------------
+/**
+ * Computes the union of one or more arrays
+ * @param {...any[]} arrays One or more arrays to union
+ * @returns {any[]} The union of the input arrays
+ */
+function union(...arrays) {
+
+ // TODO(stephenwade): Replace this with arrays.flat() when we drop support for Node v10
+ return [...new Set([].concat(...arrays))];
+}
+
+/**
+ * Computes the intersection of one or more arrays
+ * @param {...any[]} arrays One or more arrays to intersect
+ * @returns {any[]} The intersection of the input arrays
+ */
+function intersection(...arrays) {
+ if (arrays.length === 0) {
+ return [];
+ }
+
+ let result = [...new Set(arrays[0])];
+
+ for (const array of arrays.slice(1)) {
+ result = result.filter(x => array.includes(x));
+ }
+ return result;
+}
+
/**
* Gets the possible types of a selector
* @param {Object} parsedSelector An object (from esquery) describing the matching behavior of the selector
const typesForComponents = parsedSelector.selectors.map(getPossibleTypes);
if (typesForComponents.every(Boolean)) {
- return lodash.union(...typesForComponents);
+ return union(...typesForComponents);
}
return null;
}
* If at least one of the components could only match a particular type, the compound could only match
* the intersection of those types.
*/
- return lodash.intersection(...typesForComponents);
+ return intersection(...typesForComponents);
}
case "child":
}
}
+const selectorCache = new Map();
+
/**
* Parses a raw selector string, and returns the parsed selector along with specificity and type information.
* @param {string} rawSelector A raw AST selector
* @returns {ASTSelector} A selector descriptor
*/
-const parseSelector = lodash.memoize(rawSelector => {
+function parseSelector(rawSelector) {
+ if (selectorCache.has(rawSelector)) {
+ return selectorCache.get(rawSelector);
+ }
+
const parsedSelector = tryParseSelector(rawSelector);
- return {
+ const result = {
rawSelector,
isExit: rawSelector.endsWith(":exit"),
parsedSelector,
attributeCount: countClassAttributes(parsedSelector),
identifierCount: countIdentifiers(parsedSelector)
};
-});
+
+ selectorCache.set(rawSelector, result);
+ return result;
+}
//------------------------------------------------------------------------------
// Public Interface