| 170 | * target. |
| 171 | */ |
| 172 | export class R3TargetBinder<DirectiveT extends DirectiveMeta> implements TargetBinder<DirectiveT> { |
| 173 | constructor(private directiveMatcher: DirectiveMatcher<DirectiveT> | null) {} |
| 174 | |
| 175 | /** |
| 176 | * Perform a binding operation on the given `Target` and return a `BoundTarget` which contains |
| 177 | * metadata about the types referenced in the template. |
| 178 | */ |
| 179 | bind(target: Target<DirectiveT>): BoundTarget<DirectiveT> { |
| 180 | if (!target.template && !target.host) { |
| 181 | throw new Error('Empty bound targets are not supported'); |
| 182 | } |
| 183 | |
| 184 | const directives: MatchedDirectives<DirectiveT> = new Map(); |
| 185 | const eagerDirectives: DirectiveT[] = []; |
| 186 | const missingDirectives = new Set<string>(); |
| 187 | const bindings: BindingsMap<DirectiveT> = new Map(); |
| 188 | const references: ReferenceMap<DirectiveT> = new Map(); |
| 189 | const scopedNodeEntities: ScopedNodeEntities = new Map(); |
| 190 | const expressions = new Map<AST, TemplateEntity>(); |
| 191 | const symbols = new Map<TemplateEntity, Template>(); |
| 192 | const nestingLevel = new Map<ScopedNode, number>(); |
| 193 | const usedPipes = new Set<string>(); |
| 194 | const eagerPipes = new Set<string>(); |
| 195 | const deferBlocks: DeferBlockScopes = []; |
| 196 | const conflictingHostDirectiveBindings = new Map< |
| 197 | DirectiveOwner, |
| 198 | ConflictingHostDirectiveBinding<DirectiveT>[] |
| 199 | >(); |
| 200 | |
| 201 | if (target.template) { |
| 202 | // First, parse the template into a `Scope` structure. This operation captures the syntactic |
| 203 | // scopes in the template and makes them available for later use. |
| 204 | const scope = Scope.apply(target.template); |
| 205 | |
| 206 | // Use the `Scope` to extract the entities present at every level of the template. |
| 207 | extractScopedNodeEntities(scope, scopedNodeEntities); |
| 208 | |
| 209 | // Next, perform directive matching on the template using the `DirectiveBinder`. This returns: |
| 210 | // - directives: Map of nodes (elements & ng-templates) to the directives on them. |
| 211 | // - bindings: Map of inputs, outputs, and attributes to the directive/element that claims |
| 212 | // them. TODO(alxhub): handle multiple directives claiming an input/output/etc. |
| 213 | // - references: Map of #references to their targets. |
| 214 | DirectiveBinder.apply( |
| 215 | target.template, |
| 216 | this.directiveMatcher, |
| 217 | directives, |
| 218 | eagerDirectives, |
| 219 | missingDirectives, |
| 220 | bindings, |
| 221 | references, |
| 222 | conflictingHostDirectiveBindings, |
| 223 | ); |
| 224 | |
| 225 | // Finally, run the TemplateBinder to bind references, variables, and other entities within the |
| 226 | // template. This extracts all the metadata that doesn't depend on directive matching. |
| 227 | TemplateBinder.applyWithScope( |
| 228 | target.template, |
| 229 | scope, |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…