UNPKG

@adguard/aglint

Version:

Universal adblock filter list linter.

287 lines (286 loc) 9.61 kB
import { type AdblockSyntax, type AnyRule, type Node, type Value } from '@adguard/agtree'; import { type Struct } from 'superstruct'; import { type CssTreeParsingContext, type CssTreeParsingContextToNode } from './helpers/css-tree-types'; import { type AnySeverity } from './severity'; /** * Represents any linter rule. */ export type AnyLinterRule = LinterRule<any, any>; /** * Type for rule configuration object. */ export type LinterRuleConfigObject = { [key: string]: LinterRuleConfig; }; /** * Type definition for the linter rule config, which can be: * - severity itself (number or string): `severity` * - one-element array with severity as the first element: `[severity]` * - n-element array with severity as the first element and other options as the rest: `[severity, ...options]`. */ export type LinterRuleConfig = AnySeverity | LinterRuleConfigArray; /** * Type definition for the linter rule config array, which can be: * - one-element array with severity as the first element: `[severity]` * - n-element array with severity as the first element and other options as the rest: `[severity, ...options]`. */ export type LinterRuleConfigArray = [AnySeverity, ...unknown[]]; /** * Represents the metadata of a linter rule configuration. */ export interface LinterRuleConfigMeta { /** * Default configuration of the rule. */ default: unknown; /** * Superstruct schema for the rule configuration (used for validation). */ schema: Struct; } /** * Represents the metadata of a linter rule. */ export interface LinterRuleMeta { /** * Linter rule severity. It can be off, warn, error or fatal. */ severity: AnySeverity; /** * Configuration metadata (if the rule has any configuration). */ config?: LinterRuleConfigMeta; } /** * Represents what events a linter rule can handle. */ export interface LinterRuleEvents<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> { /** * Called before analyzing a filter list (before any rule is analyzed). * You can retrieve the filter list and other necessary information from the context. * * @param context Linter context. */ onStartFilterList?: (context: GenericRuleContext<StorageType, ConfigType>) => void; /** * Called after analyzing a filter list (after all rules are analyzed). * You can retrieve the filter list and other necessary information from the context. * * @param context Linter context. */ onEndFilterList?: (context: GenericRuleContext<StorageType, ConfigType>) => void; /** * Called when analyzing an adblock rule. This event is called for each rule, including comments. * You can retrieve the adblock rule and other necessary information from the context. * * @param context Linter context. */ onRule?: (context: SpecificRuleContext<StorageType, ConfigType>) => void; } /** * Represents an AGLint rule. */ export interface LinterRule<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> { /** * Basic data of the rule (metadata). */ meta: LinterRuleMeta; /** * Events belonging to the rule. */ events: LinterRuleEvents<StorageType, ConfigType>; } /** * Represents the core linter configuration. */ export interface LinterConfig { /** * Root configuration flag. If it's value is true, the configuration is root configuration. */ root?: boolean; /** * Whether to allow inline configuration or not. * * @example * ```adblock * ! aglint-disable-next-line * ``` */ allowInlineConfig?: boolean; /** * An array of configuration presets to extend. */ extends?: string[]; /** * Specific adblock syntaxes to use for network rule modifiers validation. * Array of strings: * - `['Common']` (default) * - or any combination of `['AdGuard', 'uBlockOrigin', 'AdblockPlus']`. * * Can be set in the configuration file * or in the filter list as `Agent` type comment. * */ syntax: AdblockSyntax[]; /** * A map of rule names to their configuration. */ rules?: LinterRuleConfigObject; } /** * Type definition for the linter rule context getter function. * * @param rawValueNode The raw value node. * @param context The context, see {@link CssTreeParsingContext}. * * @returns The CSS node or `null` if the CSS could not be parsed. */ type CssNodeGetter = <T extends CssTreeParsingContext>(rawValueNode: Value<string>, context: T) => CssTreeParsingContextToNode[T] | null; /** * Represents a linter context that is passed to the rules when their events are triggered. */ export interface GenericRuleContext<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> { /** * Returns the clone of the shared linter configuration. * * @returns The shared linter configuration. */ getLinterConfig: () => LinterConfig; /** * Returns the raw content of the adblock filter list currently processed by the linter. * * @returns The raw adblock filter list content. */ getFilterListContent: () => string; /** * Returns whether a fix was requested from the linter. This is an optimization * for the linter, so it doesn't have to run the fixer if it's not needed. * * @returns `true` if fix is needed, `false` otherwise. */ fixingEnabled: () => boolean; /** * Storage for storing data between events. This storage is only visible to the rule. */ storage: StorageType; /** * Additional config for the rule. This is unknown at this point, but the concrete * type is defined by the rule. */ config: ConfigType; /** * Function for reporting problems to the linter. * * @param problem The problem to report. */ report: (problem: LinterProblemReport) => void; /** * Returns the CSS node for the given raw value node and context. * * @param rawValueNode The raw value node. * @param context The context, see {@link CssTreeParsingContext}. * For more information, please check https://github.com/csstree/csstree/blob/master/docs/parsing.md#context. * * @returns The CSS node or `null` if the CSS could not be parsed. * * @note When you call this function from a rule and it cannot parse the CSS, * it will automatically report a problem to the linter and marks your linter rule as the source. * Reported problem will have the same severity as the rule. */ getCssNode: CssNodeGetter; } /** * Specialized linter context for the rule that is triggered when analyzing an adblock rule. */ export interface SpecificRuleContext<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> extends GenericRuleContext<StorageType, ConfigType> { /** * Returns the AST of the adblock rule currently being iterated by the linter. * * @returns The actual adblock rule as AST. */ getActualAdblockRuleAst: () => AnyRule; /** * Returns the raw version of the adblock rule currently being iterated by the linter. * * @returns The actual adblock rule as original string. */ getActualAdblockRuleRaw: () => string; /** * Returns the line number that the linter is currently iterating. * * @returns The actual line number. */ getActualLine: () => number; } /** * Represents the location of a problem that detected by the linter. */ export interface LinterPosition { /** * 1-based line number of the problem. */ startLine: number; /** * 0-based column number of the problem. */ startColumn: number; /** * 1-based line number of the problem. */ endLine: number; /** * 0-based column number of the problem. */ endColumn: number; } /** * Represents a problem report (this must be passed to context.report from the rules). */ export interface LinterProblemReport { /** * Text description of the problem. */ message: string; /** * Node that caused the problem. If provided, the linter will use its offsets to determine the problem location. */ node?: Node; /** * Relative start offset to the start of the node that caused the problem. * Useful when you do not want to mark the whole node as problematic. * * @note Only takes effect when `node` is provided. */ relativeNodeStartOffset?: number; /** * Relative start offset to the start of the node that caused the problem. * Useful when you do not want to mark the whole node as problematic. * * @note Only takes effect when `node` is provided. */ relativeNodeEndOffset?: number; /** * The location of the problem. */ position?: LinterPosition; /** * Suggested fix for the problem. */ fix?: AnyRule | AnyRule[]; /** * Severity of the problem, overrides the rule severity set in the meta property. * Needed for modifiers validation, e.g. deprecated modifiers which are still supported * but will not be supported in the future, so they are not recommended to use. */ customSeverity?: AnySeverity; } /** * Represents a linter rule storage object that is passed as reference to * the rules when their events are triggered. * * Basically used internally by the linter, so no need to export this. */ export interface LinterRuleStorage<T = unknown> { [key: string]: T; } export {};