Skip to content

Commit adbea7b

Browse files
crisbetoAndrewKushnir
authored andcommitted
refactor(compiler): expose utility for creating CSS selectors from AST nodes (#52726)
When doing directive matching in the compiler, we need to be able to create a selector from an AST node. We already have the utility, but these changes simplify the public API and expose it so it can be used in `compiler-cli`. PR Close #52726
1 parent 2d41b33 commit adbea7b

File tree

4 files changed

+34
-32
lines changed

4 files changed

+34
-32
lines changed

packages/compiler/src/compiler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export * from './render3/view/api';
6767
export {BoundAttribute as TmplAstBoundAttribute, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, Element as TmplAstElement, Icu as TmplAstIcu, Node as TmplAstNode, RecursiveVisitor as TmplAstRecursiveVisitor, Reference as TmplAstReference, Template as TmplAstTemplate, Text as TmplAstText, TextAttribute as TmplAstTextAttribute, Variable as TmplAstVariable, DeferredBlock as TmplAstDeferredBlock, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockError as TmplAstDeferredBlockError, DeferredTrigger as TmplAstDeferredTrigger, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, DeferredBlockTriggers as TmplAstDeferredBlockTriggers, UnknownBlock as TmplAstUnknownBlock} from './render3/r3_ast';
6868
export * from './render3/view/t2_api';
6969
export * from './render3/view/t2_binder';
70+
export {createCssSelectorFromNode} from './render3/view/util';
7071
export {Identifiers as R3Identifiers} from './render3/r3_identifiers';
7172
export {R3ClassMetadata, CompileClassMetadataFn, compileClassMetadata, compileComponentClassMetadata} from './render3/r3_class_metadata_compiler';
7273
export {compileClassDebugInfo, R3ClassDebugInfo} from './render3/r3_class_debug_info_compiler';

packages/compiler/src/render3/view/t2_binder.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {SelectorMatcher} from '../../selector';
1111
import {BoundAttribute, BoundEvent, BoundText, Comment, Content, DeferredBlock, DeferredBlockError, DeferredBlockLoading, DeferredBlockPlaceholder, DeferredTrigger, Element, ForLoopBlock, ForLoopBlockEmpty, HoverDeferredTrigger, Icu, IfBlock, IfBlockBranch, InteractionDeferredTrigger, Node, Reference, SwitchBlock, SwitchBlockCase, Template, Text, TextAttribute, UnknownBlock, Variable, ViewportDeferredTrigger, Visitor} from '../r3_ast';
1212

1313
import {BoundTarget, DirectiveMeta, ReferenceTarget, ScopedNode, Target, TargetBinder} from './t2_api';
14-
import {createCssSelector} from './template';
15-
import {getAttrsForDirectiveMatching} from './util';
14+
import {createCssSelectorFromNode} from './util';
1615

1716
/**
1817
* Processes `Target`s with a given set of directives and performs a binding operation, which
@@ -307,17 +306,17 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor {
307306
}
308307

309308
visitElement(element: Element): void {
310-
this.visitElementOrTemplate(element.name, element);
309+
this.visitElementOrTemplate(element);
311310
}
312311

313312
visitTemplate(template: Template): void {
314-
this.visitElementOrTemplate('ng-template', template);
313+
this.visitElementOrTemplate(template);
315314
}
316315

317-
visitElementOrTemplate(elementName: string, node: Element|Template): void {
316+
visitElementOrTemplate(node: Element|Template): void {
318317
// First, determine the HTML shape of the node for the purpose of directive matching.
319318
// Do this by building up a `CssSelector` for the node.
320-
const cssSelector = createCssSelector(elementName, getAttrsForDirectiveMatching(node));
319+
const cssSelector = createCssSelectorFromNode(node);
321320

322321
// Next, use the `SelectorMatcher` to get the list of directives on the node.
323322
const directives: DirectiveT[] = [];

packages/compiler/src/render3/view/template.ts

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2570,30 +2570,6 @@ class TrackByBindingScope extends BindingScope {
25702570
}
25712571
}
25722572

2573-
/**
2574-
* Creates a `CssSelector` given a tag name and a map of attributes
2575-
*/
2576-
export function createCssSelector(
2577-
elementName: string, attributes: {[name: string]: string}): CssSelector {
2578-
const cssSelector = new CssSelector();
2579-
const elementNameNoNs = splitNsName(elementName)[1];
2580-
2581-
cssSelector.setElement(elementNameNoNs);
2582-
2583-
Object.getOwnPropertyNames(attributes).forEach((name) => {
2584-
const nameNoNs = splitNsName(name)[1];
2585-
const value = attributes[name];
2586-
2587-
cssSelector.addAttribute(nameNoNs, value);
2588-
if (name.toLowerCase() === 'class') {
2589-
const classes = value.trim().split(/\s+/);
2590-
classes.forEach(className => cssSelector.addClassName(className));
2591-
}
2592-
});
2593-
2594-
return cssSelector;
2595-
}
2596-
25972573
/**
25982574
* Creates an array of expressions out of an `ngProjectAs` attributes
25992575
* which can be added to the instruction parameters.

packages/compiler/src/render3/view/util.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
import {ConstantPool} from '../../constant_pool';
1010
import {BindingType, Interpolation} from '../../expression_parser/ast';
11+
import {splitNsName} from '../../ml_parser/tags';
1112
import * as o from '../../output/output_ast';
1213
import {ParseSourceSpan} from '../../parse_util';
14+
import {CssSelector} from '../../selector';
1315
import * as t from '../r3_ast';
1416
import {Identifiers as R3} from '../r3_identifiers';
1517
import {ForwardRefHandling} from '../util';
@@ -277,6 +279,31 @@ export class DefinitionMap<T = any> {
277279
}
278280
}
279281

282+
/**
283+
* Creates a `CssSelector` from an AST node.
284+
*/
285+
export function createCssSelectorFromNode(node: t.Element|t.Template): CssSelector {
286+
const elementName = node instanceof t.Element ? node.name : 'ng-template';
287+
const attributes = getAttrsForDirectiveMatching(node);
288+
const cssSelector = new CssSelector();
289+
const elementNameNoNs = splitNsName(elementName)[1];
290+
291+
cssSelector.setElement(elementNameNoNs);
292+
293+
Object.getOwnPropertyNames(attributes).forEach((name) => {
294+
const nameNoNs = splitNsName(name)[1];
295+
const value = attributes[name];
296+
297+
cssSelector.addAttribute(nameNoNs, value);
298+
if (name.toLowerCase() === 'class') {
299+
const classes = value.trim().split(/\s+/);
300+
classes.forEach(className => cssSelector.addClassName(className));
301+
}
302+
});
303+
304+
return cssSelector;
305+
}
306+
280307
/**
281308
* Extract a map of properties to values for a given element or template node, which can be used
282309
* by the directive matching machinery.
@@ -286,8 +313,7 @@ export class DefinitionMap<T = any> {
286313
* object maps a property name to its (static) value. For any bindings, this map simply maps the
287314
* property name to an empty string.
288315
*/
289-
export function getAttrsForDirectiveMatching(elOrTpl: t.Element|
290-
t.Template): {[name: string]: string} {
316+
function getAttrsForDirectiveMatching(elOrTpl: t.Element|t.Template): {[name: string]: string} {
291317
const attributesMap: {[name: string]: string} = {};
292318

293319

0 commit comments

Comments
 (0)