refactor: ValueCleaner is the named choke point (H1)
The choke point moves out of AttrWriter into ValueCleaner (catalog, the composition's VariableRef, sanitizer): clean() (was AttrWriter::cleanValue), kindOf(), guardPath() and the private cleanNode/kind/unknownKind/tightens with VALUE_KEY, URL_KEY, URL_SEGMENT, STRICTNESS, BUILDER_ONLY (its docblock now sits on it; STRUCTURE stays in AttrWriter). Code of the pipeline moved unchanged. - ValueCleaner's docblock is the one canonical description: steps 0-8 with their rulings in code order, invariants I1-I3; the step comments in cleanNode carry the same numbers. AttrWriter/ShortformWriter/Composer/TextReplacer docblocks point there and keep only their own rules. - ValueCleaner::textReplacementFor($module) holds the D10 rule that was a closure in DiviReplaceTextAbility::replace (text/html only, clean() by kind). - AttrWriter, ShortformWriter and Composer take the ValueCleaner; DiviComposition builds one per composition (cleaner()). Tests: the eight AttrWriterTest methods that only exercised cleanValue/kindOf moved verbatim to ValueCleanerTest (clean/kindOf, ComposeFixture::cleaner()); mixed tests call the cleaner in place; +1 test for textReplacementFor. Every provider row and per-test assertion count unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -30,7 +30,7 @@ use WP_Error;
|
||||
* it is written; DiviWriter::save() stores it with its own restore-point revision and change
|
||||
* log. The batch reports every page (spec §8.2, ruling S10): any Throwable of one page is logged
|
||||
* and reported there, the others go on. Inserted text is cleaned by the field kind through
|
||||
* AttrWriter::cleanValue() (S2/S28); URL and code fields are never touched.
|
||||
* ValueCleaner::textReplacementFor() (S2/S28); URL and code fields are never touched.
|
||||
*/
|
||||
final class DiviReplaceTextAbility implements Ability
|
||||
{
|
||||
@@ -379,7 +379,7 @@ final class DiviReplaceTextAbility implements Ability
|
||||
|
||||
/**
|
||||
* Every hit of $page, computed without changing it. The replacement is cleaned per place by
|
||||
* the entry's AttrWriter (field kind; markers rejected); URL and code fields are skipped.
|
||||
* the entry's ValueCleaner (field kind; markers rejected); URL and code fields are skipped.
|
||||
*
|
||||
* @return array{count: int, samples: list<array<string, string>>,
|
||||
* blocks: list<array{Block, array<string, mixed>}>, skipped_nodes: list<array{id: string, reason: string}>}
|
||||
@@ -387,7 +387,7 @@ final class DiviReplaceTextAbility implements Ability
|
||||
*/
|
||||
private function replace(DiviPage $page, TextReplacer $replacer): array
|
||||
{
|
||||
$attrWriter = $this->writer->composition($page)->attrWriter();
|
||||
$cleaner = $this->writer->composition($page)->cleaner();
|
||||
$count = 0;
|
||||
$samples = [];
|
||||
$blocks = [];
|
||||
@@ -404,16 +404,8 @@ final class DiviReplaceTextAbility implements Ability
|
||||
continue;
|
||||
}
|
||||
|
||||
$module = $block->name();
|
||||
$clean = static function (string $path, ?string $key, string $value) use ($attrWriter, $module): ?string {
|
||||
$kind = $attrWriter->kindOf($module, $path, $key);
|
||||
|
||||
return $kind === 'text' || $kind === 'html'
|
||||
? (string) $attrWriter->cleanValue($module, $path, $value, $key)
|
||||
: null;
|
||||
};
|
||||
try {
|
||||
$result = $replacer->apply($block->attrs(), $clean);
|
||||
$result = $replacer->apply($block->attrs(), $cleaner->textReplacementFor($block->name()));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException(sprintf('Knoten %s: %s', $entry['id'], $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user