@adguard/aglint
Version:
Universal adblock filter list linter.
86 lines (83 loc) • 4.14 kB
JavaScript
/*
* AGLint v3.0.0 (build date: Wed, 21 May 2025 13:24:14 GMT)
* (c) 2025 AdGuard Software Ltd.
* Released under the MIT license
* https://github.com/AdguardTeam/AGLint#readme
*/
import equal from 'fast-deep-equal';
import { RuleCategory, CommentRuleType } from '@adguard/agtree';
import { SEVERITY } from '../severity.js';
const PLATFORM = 'PLATFORM';
const NOT_PLATFORM = 'NOT_PLATFORM';
/**
* Rule that checks if a platform targeted by a PLATFORM() hint is also excluded by a NOT_PLATFORM()
* hint at the same time.
*/
const InconsistentHintPlatforms = {
meta: {
severity: SEVERITY.error,
},
events: {
onRule: (context) => {
// Get actually iterated adblock rule
const ast = context.getActualAdblockRuleAst();
if (ast.category === RuleCategory.Comment && ast.type === CommentRuleType.HintCommentRule) {
// Only makes sense to check this, if there are at least two hints within the comment
if (ast.children.length < 2) {
return;
}
// Platforms targeted by a PLATFORM() hint
const platforms = [];
// Platforms excluded by a NOT_PLATFORM() hint
const notPlatforms = [];
// Iterate over all hints within the hint comment rule
for (const hint of ast.children) {
for (const param of hint.params?.children ?? []) {
if (!param) {
continue;
}
// Add actual platform (parameter) to the corresponding array
if (hint.name.value === PLATFORM) {
platforms.push(param);
}
else if (hint.name.value === NOT_PLATFORM) {
notPlatforms.push(param);
}
}
}
// Find platforms that are targeted by a PLATFORM() hint and excluded by a
// NOT_PLATFORM() hint at the same time, but take duplicates into account
const commonPlatforms = [];
for (const platform of platforms) {
for (const notPlatform of notPlatforms) {
if (platform.value === notPlatform.value) {
// Check if the platform is already in the array (loc property is unique
// and definietly exists, since we configured the parser to do so)
if (!commonPlatforms.some((e) => equal(e.start, platform.start))) {
commonPlatforms.push(platform);
}
if (!commonPlatforms.some((e) => equal(e.start, notPlatform.start))) {
commonPlatforms.push(notPlatform);
}
}
}
}
// Sort platforms by their location ("loc.start.offset") to get a consistent order
// It is safe to use the non-null assertion operator here, because the loc property
// is always defined for parameters, since we configured the parser to do so
// eslint-disable-next-line max-len, @typescript-eslint/no-non-null-assertion
const commonPlatformsOrdered = commonPlatforms.sort((a, b) => a.start - b.start);
// Report all platforms that are targeted by a PLATFORM() hint and excluded by a
// NOT_PLATFORM() hint at the same time
for (const platform of commonPlatformsOrdered) {
context.report({
// eslint-disable-next-line max-len
message: `Platform "${platform.value}" is targeted by a PLATFORM() hint and excluded by a NOT_PLATFORM() hint at the same time`,
node: platform,
});
}
}
},
},
};
export { InconsistentHintPlatforms };