*/ public array $http_headers = []; /** @var array map of xpath => wrapper spec e.g. "div.foo" */ public array $wrap_in = []; public bool $prune = true; public bool $tidy = true; public bool $autodetect_on_failure = true; /** * Files this rule was assembled from, nearest-match first. Surfaced in the * UI so a stale rule is visible rather than silently falling through to * Readability -- the exact failure mode that hid a broken comic rule for * years. * * @var string[] */ public array $sources = []; public function is_empty(): bool { return !$this->bodies && !$this->strips && !$this->strip_id_or_class && !$this->strip_image_src && !$this->titles && !$this->dissolve; } /** Merge $other UNDER $this: existing scalars win, list directives concatenate. */ public function merge_under(self $other): self { $m = clone $this; foreach (['titles', 'bodies', 'authors', 'dates', 'single_page_links', 'next_page_links'] as $f) if (!$m->$f) $m->$f = $other->$f; foreach (['strips', 'strip_id_or_class', 'strip_image_src', 'dissolve', 'test_urls'] as $f) $m->$f = array_values(array_unique([...$m->$f, ...$other->$f])); // find/replace are positional pairs -- appending keeps them aligned. $m->find_strings = [...$m->find_strings, ...$other->find_strings]; $m->replace_strings = [...$m->replace_strings, ...$other->replace_strings]; $m->http_headers = $m->http_headers + $other->http_headers; $m->wrap_in = $m->wrap_in + $other->wrap_in; $m->sources = [...$m->sources, ...$other->sources]; return $m; } }