@adguard/agtree
Version:
Tool set for working with adblock filter lists
71 lines (68 loc) • 3.24 kB
JavaScript
/*
* AGTree v3.2.2 (build date: Tue, 08 Jul 2025 13:39:47 GMT)
* (c) 2025 Adguard Software Ltd.
* Released under the MIT license
* https://github.com/AdguardTeam/tsurlfilter/tree/master/packages/agtree#readme
*/
import { MODIFIERS_SEPARATOR } from '../../utils/constants.js';
import { StringUtils } from '../../utils/string.js';
import { BaseParser } from '../base-parser.js';
import { defaultParserOptions } from '../options.js';
import { ModifierParser } from './modifier-parser.js';
/* eslint-disable no-param-reassign */
/**
* `ModifierListParser` is responsible for parsing modifier lists. Please note that the name is not
* uniform, "modifiers" are also known as "options".
*
* @see {@link https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#basic-rules-modifiers}
* @see {@link https://kb.adguard.com/en/general/how-to-create-your-own-ad-filters#non-basic-rules-modifiers}
* @see {@link https://help.eyeo.com/adblockplus/how-to-write-filters#options}
*/
class ModifierListParser extends BaseParser {
/**
* Parses the cosmetic rule modifiers, eg. `third-party,domain=example.com|~example.org`.
*
* _Note:_ you should remove `$` separator before passing the raw modifiers to this function,
* or it will be parsed in the first modifier.
*
* @param raw Raw input to parse.
* @param options Global parser options.
* @param baseOffset Starting offset of the input. Node locations are calculated relative to this offset.
* @returns Parsed modifiers interface
*/
static parse(raw, options = defaultParserOptions, baseOffset = 0) {
const result = {
type: 'ModifierList',
children: [],
};
if (options.isLocIncluded) {
result.start = baseOffset;
result.end = baseOffset + raw.length;
}
let offset = StringUtils.skipWS(raw);
let separatorIndex = -1;
// Split modifiers by unescaped commas
while (offset < raw.length) {
// Skip whitespace before the modifier
offset = StringUtils.skipWS(raw, offset);
const modifierStart = offset;
// Find the index of the first unescaped comma
separatorIndex = StringUtils.findNextUnescapedCharacter(raw, MODIFIERS_SEPARATOR, offset);
const modifierEnd = separatorIndex === -1
? raw.length
: StringUtils.skipWSBack(raw, separatorIndex - 1) + 1;
// Parse the modifier
const modifier = ModifierParser.parse(raw.slice(modifierStart, modifierEnd), options, baseOffset + modifierStart);
result.children.push(modifier);
// Increment the offset to the next modifier (or the end of the string)
offset = separatorIndex === -1 ? raw.length : separatorIndex + 1;
}
// Check if there are any modifiers after the last separator
if (separatorIndex !== -1) {
const modifierStart = StringUtils.skipWS(raw, separatorIndex + 1);
result.children.push(ModifierParser.parse(raw.slice(modifierStart, raw.length), options, baseOffset + modifierStart));
}
return result;
}
}
export { ModifierListParser };