From d321b0ebf5fa020ac7aecd4d718479a862e0b920 Mon Sep 17 00:00:00 2001 From: Dzmitry Shylovich Date: Tue, 18 Oct 2016 01:19:18 +0300 Subject: [PATCH] fix(selectors): use Maps instead of objects --- modules/@angular/compiler/src/selector.ts | 50 +++++++++---------- .../@angular/compiler/test/selector_spec.ts | 6 +++ 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/modules/@angular/compiler/src/selector.ts b/modules/@angular/compiler/src/selector.ts index df3878627d..b38ebde40f 100644 --- a/modules/@angular/compiler/src/selector.ts +++ b/modules/@angular/compiler/src/selector.ts @@ -135,12 +135,12 @@ export class SelectorMatcher { return notMatcher; } - private _elementMap: {[k: string]: SelectorContext[]} = {}; - private _elementPartialMap: {[k: string]: SelectorMatcher} = {}; - private _classMap: {[k: string]: SelectorContext[]} = {}; - private _classPartialMap: {[k: string]: SelectorMatcher} = {}; - private _attrValueMap: {[k: string]: {[k: string]: SelectorContext[]}} = {}; - private _attrValuePartialMap: {[k: string]: {[k: string]: SelectorMatcher}} = {}; + 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) { @@ -195,18 +195,18 @@ export class SelectorMatcher { const value = attrs[i + 1]; if (isTerminal) { const terminalMap = matcher._attrValueMap; - let terminalValuesMap = terminalMap[name]; + let terminalValuesMap = terminalMap.get(name); if (!terminalValuesMap) { - terminalValuesMap = {}; - terminalMap[name] = terminalValuesMap; + terminalValuesMap = new Map(); + terminalMap.set(name, terminalValuesMap); } this._addTerminal(terminalValuesMap, value, selectable); } else { let partialMap = matcher._attrValuePartialMap; - let partialValuesMap = partialMap[name]; + let partialValuesMap = partialMap.get(name); if (!partialValuesMap) { - partialValuesMap = {}; - partialMap[name] = partialValuesMap; + partialValuesMap = new Map(); + partialMap.set(name, partialValuesMap); } matcher = this._addPartial(partialValuesMap, value); } @@ -215,20 +215,20 @@ export class SelectorMatcher { } private _addTerminal( - map: {[k: string]: SelectorContext[]}, name: string, selectable: SelectorContext) { - let terminalList = map[name]; + map: Map, name: string, selectable: SelectorContext) { + let terminalList = map.get(name); if (!terminalList) { terminalList = []; - map[name] = terminalList; + map.set(name, terminalList); } terminalList.push(selectable); } - private _addPartial(map: {[k: string]: SelectorMatcher}, name: string): SelectorMatcher { - let matcher = map[name]; + private _addPartial(map: Map, name: string): SelectorMatcher { + let matcher = map.get(name); if (!matcher) { matcher = new SelectorMatcher(); - map[name] = matcher; + map.set(name, matcher); } return matcher; } @@ -270,7 +270,7 @@ export class SelectorMatcher { const name = attrs[i]; const value = attrs[i + 1]; - const terminalValuesMap = this._attrValueMap[name]; + const terminalValuesMap = this._attrValueMap.get(name); if (value) { result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result; @@ -278,7 +278,7 @@ export class SelectorMatcher { result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result; - const partialValuesMap = this._attrValuePartialMap[name]; + const partialValuesMap = this._attrValuePartialMap.get(name); if (value) { result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result; } @@ -291,14 +291,14 @@ export class SelectorMatcher { /** @internal */ _matchTerminal( - map: {[k: string]: SelectorContext[]}, name: string, cssSelector: CssSelector, + map: Map, name: string, cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean { if (!map || typeof name !== 'string') { return false; } - let selectables = map[name]; - const starSelectables = map['*']; + let selectables = map.get(name); + const starSelectables = map.get('*'); if (starSelectables) { selectables = selectables.concat(starSelectables); } @@ -316,13 +316,13 @@ export class SelectorMatcher { /** @internal */ _matchPartial( - map: {[k: string]: SelectorMatcher}, name: string, cssSelector: CssSelector, + map: Map, name: string, cssSelector: CssSelector, matchedCallback: (c: CssSelector, a: any) => void): boolean { if (!map || typeof name !== 'string') { return false; } - const nestedSelector = map[name]; + const nestedSelector = map.get(name); if (!nestedSelector) { return false; } diff --git a/modules/@angular/compiler/test/selector_spec.ts b/modules/@angular/compiler/test/selector_spec.ts index b6491e4876..b7bd8e1d22 100644 --- a/modules/@angular/compiler/test/selector_spec.ts +++ b/modules/@angular/compiler/test/selector_spec.ts @@ -58,6 +58,12 @@ export function main() { expect(matched).toEqual([s1[0], 1, s2[0], 2]); }); + it('should not throw for class name "constructor"', () => { + expect(matcher.match(CssSelector.parse('.constructor')[0], selectableCollector)) + .toEqual(false); + expect(matched).toEqual([]); + }); + it('should select by attr name case sensitive independent of the value', () => { matcher.addSelectables(s1 = CssSelector.parse('[someAttr]'), 1); matcher.addSelectables(s2 = CssSelector.parse('[someAttr][someAttr2]'), 2);