Resolve a template name and return composed content. Walks the priority stack and composes content using strategies: - replace (default): highest-priority content wins entirely - prepend: content is placed before lower-priority content - append: content is placed aft
(
self,
template_name: str,
template_type: str = "template",
)
| 3131 | return None |
| 3132 | |
| 3133 | def resolve_content( |
| 3134 | self, |
| 3135 | template_name: str, |
| 3136 | template_type: str = "template", |
| 3137 | ) -> Optional[str]: |
| 3138 | """Resolve a template name and return composed content. |
| 3139 | |
| 3140 | Walks the priority stack and composes content using strategies: |
| 3141 | - replace (default): highest-priority content wins entirely |
| 3142 | - prepend: content is placed before lower-priority content |
| 3143 | - append: content is placed after lower-priority content |
| 3144 | - wrap: content contains {CORE_TEMPLATE} placeholder replaced |
| 3145 | with lower-priority content (or $CORE_SCRIPT for scripts) |
| 3146 | |
| 3147 | Composition is recursive — multiple composing presets chain. |
| 3148 | |
| 3149 | Args: |
| 3150 | template_name: Template name (e.g., "spec-template") |
| 3151 | template_type: Template type ("template", "command", or "script") |
| 3152 | |
| 3153 | Returns: |
| 3154 | Composed content string, or None if not found |
| 3155 | """ |
| 3156 | layers = self.collect_all_layers(template_name, template_type) |
| 3157 | if not layers: |
| 3158 | return None |
| 3159 | |
| 3160 | # If the top (highest-priority) layer is replace, it wins entirely — |
| 3161 | # lower layers are irrelevant regardless of their strategies. |
| 3162 | if layers[0]["strategy"] == "replace": |
| 3163 | return layers[0]["path"].read_text(encoding="utf-8") |
| 3164 | |
| 3165 | # Composition: build content bottom-up from the effective base. |
| 3166 | # The base is the nearest replace layer scanning from highest priority |
| 3167 | # downward. Only layers above the base contribute to composition. |
| 3168 | # |
| 3169 | # layers is ordered highest-priority first. We process in reverse. |
| 3170 | reversed_layers = list(reversed(layers)) |
| 3171 | |
| 3172 | # Find the effective base: scan from highest priority (layers[0]) downward |
| 3173 | # to find the nearest replace layer. Only compose layers above that base. |
| 3174 | # layers is highest-priority first; reversed_layers is lowest first. |
| 3175 | base_layer_idx = None # index in layers[] (highest-priority first) |
| 3176 | for idx, layer in enumerate(layers): |
| 3177 | if layer["strategy"] == "replace": |
| 3178 | base_layer_idx = idx |
| 3179 | break |
| 3180 | |
| 3181 | if base_layer_idx is None: |
| 3182 | return None # no replace base found |
| 3183 | |
| 3184 | # Convert to reversed_layers index |
| 3185 | base_reversed_idx = len(layers) - 1 - base_layer_idx |
| 3186 | content = layers[base_layer_idx]["path"].read_text(encoding="utf-8") |
| 3187 | # Compose only the layers above the base (higher priority = lower index in layers, |
| 3188 | # higher index in reversed_layers). Process bottom-up from base+1. |
| 3189 | start_idx = base_reversed_idx + 1 |
| 3190 |