Skip to content

Commit

Permalink
refactor Detector
Browse files Browse the repository at this point in the history
  • Loading branch information
cmrn authored and clshortfuse committed Aug 23, 2024
1 parent efa8d04 commit 7765bc3
Showing 1 changed file with 48 additions and 34 deletions.
82 changes: 48 additions & 34 deletions lib/Detector.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import FEATURES from '../data/features.js';
import { performFeatureCheck, stripUrls } from '../utils/util.js';

/** @typedef {import('../data/features.js').FeatureKeys} FeatureKeys */
/** @typedef {import('../data/features.js').RuleCheck} RuleCheck */

/**
* @typedef DetectorCallbackArgument
* @prop {!import('postcss').ChildNode} usage
* @prop {keyof FEATURES} feature
* @prop {(keyof FEATURES & string)[]} ignore
* @prop {FeatureKeys} feature
* @prop {(FeatureKeys & string)[]} ignore
*/

/**
Expand All @@ -18,6 +21,35 @@ const PLUGIN_OPTION_COMMENT = 'doiuse-';
const DISABLE_FEATURE_COMMENT = `${PLUGIN_OPTION_COMMENT}disable`;
const ENABLE_FEATURE_COMMENT = `${PLUGIN_OPTION_COMMENT}enable`;

/**
* Normalise a Feature into a RuleCheck function.
* @param {import('../data/features.js').Feature} feature
* @return {RuleCheck}
*/
function normaliseFeature(feature) {
if (typeof feature === 'function') {
return feature;
}
if (Array.isArray(feature)) {
return (child) => feature.some((function_) => function_(child));
}
if (typeof feature === 'object') {
const properties = Object.entries(feature);
return (child) => {
if (child.type !== 'decl') {
return false;
}
return properties.some(([property, value]) => {
if (property !== '' && property !== child.prop) return false;
if (value === true) return true;
if (value === false) return false;
return performFeatureCheck(value, stripUrls(child.value));
});
};
}
throw new TypeError(`Invalid feature definition: ${feature}`);
}

/**
* Detect the use of any of a given list of CSS features.
* ```
Expand All @@ -38,17 +70,17 @@ const ENABLE_FEATURE_COMMENT = `${PLUGIN_OPTION_COMMENT}enable`;
*/
export default class Detector {
/**
* @param {(keyof FEATURES & string)[]} featureList an array of feature slugs (see caniuse-db)
* @param {(FeatureKeys & string)[]} featureList an array of feature slugs (see caniuse-db)
*/
constructor(featureList) {
/** @type {Partial<FEATURES>} */
this.features = {};
for (const feature of featureList) {
if (FEATURES[feature]) {
this.features[feature] = FEATURES[feature];
}
}
/** @type {(keyof FEATURES & string)[]} */
/** @type {[FeatureKeys, RuleCheck][]} */
this.features = featureList
.filter((featureName) => FEATURES[featureName] != null)
.map((featureName) => {
const feature = FEATURES[featureName];
return [featureName, normaliseFeature(feature)];
});
/** @type {(FeatureKeys & string)[]} */
this.ignore = [];
}

Expand All @@ -66,8 +98,7 @@ export default class Detector {
switch (option) {
case DISABLE_FEATURE_COMMENT: {
if (value === '') {
// @ts-expect-error Skip cast
this.ignore = Object.keys(this.features);
this.ignore = this.features.map(([featureName]) => featureName);
} else {
for (const feat of value.split(',')) {
/** @type {any} */
Expand Down Expand Up @@ -104,28 +135,11 @@ export default class Detector {
return;
}

for (const [feat] of Object.entries(this.features).filter(([, featValue]) => {
if (!featValue) return false;
if (typeof featValue === 'function') {
return featValue(child);
}
if (Array.isArray(featValue)) {
return featValue.some((function_) => function_(child));
}
if (child.type !== 'decl') {
return false;
}

return Object.entries(featValue).some(([property, value]) => {
if (property !== '' && property !== child.prop) return false;
if (value === true) return true;
if (value === false) return false;
return performFeatureCheck(value, stripUrls(child.value));
});
})) {
const feature = /** @type {keyof FEATURES} */ (feat);
callback({ usage: child, feature, ignore: this.ignore });
const detectedFeatures = this.features.filter(([, ruleCheck]) => ruleCheck(child));
for (const [featureName] of detectedFeatures) {
callback({ usage: child, feature: featureName, ignore: this.ignore });
}

if (child.type !== 'decl') {
this.node(child, callback);
}
Expand Down

0 comments on commit 7765bc3

Please sign in to comment.