postId = $postId; $bound->themeBuilderArea = $themeBuilderArea; $bound->references = null; $bound->placeholders = null; $bound->cleaner = null; $bound->attrWriter = null; $bound->composer = null; $bound->assignment = null; return $bound; } /** * The one checker of $variable(…)$ values of this composition, with the entry's live map (S22, S31). * * @internal Public for tests; code uses cleaner() / composer(). */ public function references(): VariableRef { return $this->references ??= new VariableRef( $this->design->read(), $this->postId === null ? null : $this->dynamicContent->forPost($this->postId) ); } /** * The one Placeholders instance of this composition (ruling S31). * * @internal Public for tests; code uses attrWriter() / composer(). */ public function placeholders(): Placeholders { return $this->placeholders ??= new Placeholders($this->design->read(), $this->links); } /** The one choke point of this composition (ValueCleaner, rulings S1–S3, S7, S13, S28, S32). */ public function cleaner(): ValueCleaner { return $this->cleaner ??= new ValueCleaner($this->modules->catalog(), $this->references(), $this->sanitizer); } public function attrWriter(): AttrWriter { return $this->attrWriter ??= new AttrWriter($this->modules->catalog(), $this->placeholders(), $this->cleaner()); } /** * The one PresetAssignment of this composition (D7, rulings R2, R3): the book comes lazily from Divi's stored * presets, ids must pass the choke point unchanged. * * @internal Public for tests; code uses composer() / warnings(). */ public function presets(): PresetAssignment { return $this->assignment ??= new PresetAssignment( fn (): PresetBook => PresetBook::fromDivi($this->presetSource?->presets() ?? []), fn (string $module): array => $this->presetSource?->groupsOf($module) ?? [], $this->cleaner()->keepsId(...) ); } public function composer(): Composer { return $this->composer ??= new Composer( $this->modules->catalog(), $this->rules(), new ShortformWriter($this->placeholders(), $this->media, $this->cleaner()), $this->attrWriter(), $this->cleaner(), $this->presets(), $this->modules->builderVersion() ); } /** @internal Public for tests; code uses composer() / editor(). */ public function rules(): StructureRules { return new StructureRules($this->modules->catalog(), $this->themeBuilderArea); } /** E6: the check for stored nodes that move into this composition's entry (same cleaner and references). */ public function storedGuard(): StoredNodeGuard { return new StoredNodeGuard($this->cleaner(), $this->references(), $this->sanitizer); } public function editor(): TreeEditor { return new TreeEditor($this->rules()); } public function warnings(): Warnings { return new Warnings($this->design->read()); } }