From a2da485d9021ece0f5e472baa7befaa1573a0c14 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Fri, 21 Sep 2018 11:43:03 -0700 Subject: [PATCH] feat(ivy): add generics to the SelectorMatcher API (#26203) This commit adds a generic type parameter to the SelectorMatcher class and its associated response types. This makes the API for matching selectors and obtaining information about the matched directives significantly more ergonomic and type-safe. PR Close #26203 --- packages/compiler/src/selector.ts | 56 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/packages/compiler/src/selector.ts b/packages/compiler/src/selector.ts index 6a69c2ff0b..aacd1d9d29 100644 --- a/packages/compiler/src/selector.ts +++ b/packages/compiler/src/selector.ts @@ -150,29 +150,29 @@ export class CssSelector { * Reads a list of CssSelectors and allows to calculate which ones * are contained in a given CssSelector. */ -export class SelectorMatcher { - static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher { - const notMatcher = new SelectorMatcher(); +export class SelectorMatcher { + static createNotMatcher(notSelectors: CssSelector[]): SelectorMatcher { + const notMatcher = new SelectorMatcher(); notMatcher.addSelectables(notSelectors, null); return notMatcher; } - private _elementMap = new Map(); - private _elementPartialMap = new Map(); - private _classMap = new Map(); - private _classPartialMap = new Map(); - private _attrValueMap = new Map>(); - private _attrValuePartialMap = new Map>(); + private _elementMap = new Map[]>(); + private _elementPartialMap = new Map>(); + private _classMap = new Map[]>(); + private _classPartialMap = new Map>(); + private _attrValueMap = new Map[]>>(); + private _attrValuePartialMap = new Map>>(); private _listContexts: SelectorListContext[] = []; - addSelectables(cssSelectors: CssSelector[], callbackCtxt?: any) { + addSelectables(cssSelectors: CssSelector[], callbackCtxt?: T) { let listContext: SelectorListContext = null !; if (cssSelectors.length > 1) { listContext = new SelectorListContext(cssSelectors); this._listContexts.push(listContext); } for (let i = 0; i < cssSelectors.length; i++) { - this._addSelectable(cssSelectors[i], callbackCtxt, listContext); + this._addSelectable(cssSelectors[i], callbackCtxt as T, listContext); } } @@ -182,8 +182,8 @@ export class SelectorMatcher { * @param callbackCtxt An opaque object that will be given to the callback of the `match` function */ private _addSelectable( - cssSelector: CssSelector, callbackCtxt: any, listContext: SelectorListContext) { - let matcher: SelectorMatcher = this; + cssSelector: CssSelector, callbackCtxt: T, listContext: SelectorListContext) { + let matcher: SelectorMatcher = this; const element = cssSelector.element; const classNames = cssSelector.classNames; const attrs = cssSelector.attrs; @@ -219,7 +219,7 @@ export class SelectorMatcher { const terminalMap = matcher._attrValueMap; let terminalValuesMap = terminalMap.get(name); if (!terminalValuesMap) { - terminalValuesMap = new Map(); + terminalValuesMap = new Map[]>(); terminalMap.set(name, terminalValuesMap); } this._addTerminal(terminalValuesMap, value, selectable); @@ -227,7 +227,7 @@ export class SelectorMatcher { const partialMap = matcher._attrValuePartialMap; let partialValuesMap = partialMap.get(name); if (!partialValuesMap) { - partialValuesMap = new Map(); + partialValuesMap = new Map>(); partialMap.set(name, partialValuesMap); } matcher = this._addPartial(partialValuesMap, value); @@ -237,7 +237,7 @@ export class SelectorMatcher { } private _addTerminal( - map: Map, name: string, selectable: SelectorContext) { + map: Map[]>, name: string, selectable: SelectorContext) { let terminalList = map.get(name); if (!terminalList) { terminalList = []; @@ -246,10 +246,10 @@ export class SelectorMatcher { terminalList.push(selectable); } - private _addPartial(map: Map, name: string): SelectorMatcher { + private _addPartial(map: Map>, name: string): SelectorMatcher { let matcher = map.get(name); if (!matcher) { - matcher = new SelectorMatcher(); + matcher = new SelectorMatcher(); map.set(name, matcher); } return matcher; @@ -262,8 +262,7 @@ export class SelectorMatcher { * @param matchedCallback This callback will be called with the object handed into `addSelectable` * @return boolean true if a match was found */ - match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: any) => void)|null): - boolean { + match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: T) => void)|null): boolean { let result = false; const element = cssSelector.element !; const classNames = cssSelector.classNames; @@ -314,21 +313,21 @@ export class SelectorMatcher { /** @internal */ _matchTerminal( - map: Map, name: string, cssSelector: CssSelector, + map: Map[]>, name: string, cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: any) => void)|null): boolean { if (!map || typeof name !== 'string') { return false; } - let selectables: SelectorContext[] = map.get(name) || []; - const starSelectables: SelectorContext[] = map.get('*') !; + let selectables: SelectorContext[] = map.get(name) || []; + const starSelectables: SelectorContext[] = map.get('*') !; if (starSelectables) { selectables = selectables.concat(starSelectables); } if (selectables.length === 0) { return false; } - let selectable: SelectorContext; + let selectable: SelectorContext; let result = false; for (let i = 0; i < selectables.length; i++) { selectable = selectables[i]; @@ -339,7 +338,7 @@ export class SelectorMatcher { /** @internal */ _matchPartial( - map: Map, name: string, cssSelector: CssSelector, + map: Map>, name: string, cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: any) => void)|null): boolean { if (!map || typeof name !== 'string') { return false; @@ -364,16 +363,15 @@ export class SelectorListContext { } // Store context to pass back selector and context when a selector is matched -export class SelectorContext { +export class SelectorContext { notSelectors: CssSelector[]; constructor( - public selector: CssSelector, public cbContext: any, - public listContext: SelectorListContext) { + public selector: CssSelector, public cbContext: T, public listContext: SelectorListContext) { this.notSelectors = selector.notSelectors; } - finalize(cssSelector: CssSelector, callback: ((c: CssSelector, a: any) => void)|null): boolean { + finalize(cssSelector: CssSelector, callback: ((c: CssSelector, a: T) => void)|null): boolean { let result = true; if (this.notSelectors.length > 0 && (!this.listContext || !this.listContext.alreadyMatched)) { const notMatcher = SelectorMatcher.createNotMatcher(this.notSelectors);