diff --git a/src/core/calculate.js b/src/core/calculate.js index a9c3f18..f05b1ae 100644 --- a/src/core/calculate.js +++ b/src/core/calculate.js @@ -34,7 +34,7 @@ const calculateForAST = (selectorAST) => { case '-webkit-any': case 'any': - if (child.children) { + if (child.children?.first) { b += 1; } break; @@ -45,7 +45,7 @@ const calculateForAST = (selectorAST) => { case 'matches': case 'not': case 'has': - if (child.children) { + if (child.children?.first) { // Calculate Specificity from nested SelectorList const max1 = max(...calculate(child.children.first)); @@ -62,7 +62,7 @@ const calculateForAST = (selectorAST) => { case 'nth-last-child': b += 1; - if (child.children && child.children.first.selector) { + if (child.children?.first?.selector) { // Calculate Specificity from SelectorList const max2 = max(...calculate(child.children.first.selector)); @@ -79,7 +79,7 @@ const calculateForAST = (selectorAST) => { case 'host': b += 1; - if (child.children) { + if (child.children?.first?.children) { // Workaround to a css-tree bug in which it allows complex selectors instead of only compound selectors // We work around it by filtering out any Combinator and successive Selectors const childAST = { type: 'Selector', children: [] }; @@ -124,7 +124,7 @@ const calculateForAST = (selectorAST) => { case 'slotted': c += 1; - if (child.children) { + if (child.children?.first?.children) { // Workaround to a css-tree bug in which it allows complex selectors instead of only compound selectors // We work around it by filtering out any Combinator and successive Selectors const childAST = { type: 'Selector', children: [] }; @@ -153,7 +153,7 @@ const calculateForAST = (selectorAST) => { case 'view-transition-old': case 'view-transition-new': // The specificity of a view-transition selector with a * argument is zero. - if (child.children && child.children.first.value === '*') { + if (child.children?.first?.value === '*') { break; } // The specificity of a view-transition selector with an argument is the same diff --git a/test/index.js b/test/index.js index 9b071b2..6d32d1f 100644 --- a/test/index.js +++ b/test/index.js @@ -83,7 +83,7 @@ describe('CALCULATE', () => { it('::slotted', () => { deepEqual(Specificity.calculate('::slotted')[0].toObject(), { a: 0, b: 0, c: 1 }); }); - it.skip('::slotted()', () => { + it('::slotted() & do not crash', () => { deepEqual(Specificity.calculate('::slotted()')[0].toObject(), { a: 0, b: 0, c: 1 }); }); it('::slotted(div#foo)', () => { @@ -105,6 +105,9 @@ describe('CALCULATE', () => { it('::view-transition', () => { deepEqual(Specificity.calculate('::view-transition')[0].toObject(), { a: 0, b: 0, c: 1 }); }); + it('::view-transition-old() & do not crash', () => { + deepEqual(Specificity.calculate('::view-transition-old()')[0].toObject(), { a: 0, b: 0, c: 1 }); + }); it('::view-transition-group(test)', () => { deepEqual(Specificity.calculate('::view-transition-group(test)')[0].toObject(), { a: 0, b: 0, c: 1 }); }); @@ -171,6 +174,9 @@ describe('CALCULATE', () => { it('p:nth-child = (0,1,1) & do not crash', () => { deepEqual(Specificity.calculate('p:nth-child')[0].toObject(), { a: 0, b: 1, c: 1 }); }); + it('p:nth-child() = (0,1,1) & do not crash', () => { + deepEqual(Specificity.calculate('p:nth-child()')[0].toObject(), { a: 0, b: 1, c: 1 }); + }); }); describe('CSS :is(), :matches(), :-moz-any = Specificity of the most specific complex selector in its selector list argument', () => { @@ -183,6 +189,9 @@ describe('CALCULATE', () => { it(':-moz-any(#foo, .bar, baz) = (1,0,0)', () => { deepEqual(Specificity.calculate(':-moz-any(#foo, .bar, baz)')[0].toObject(), { a: 1, b: 0, c: 0 }); }); + it(':has() & do not crash', () => { + deepEqual(Specificity.calculate(':has()')[0].toObject(), { a: 0, b: 0, c: 0 }); + }); }); describe('CSS :any() = (0,1,0)', () => { @@ -207,6 +216,19 @@ describe('CALCULATE', () => { it(':where = (0,0,0)', () => { deepEqual(Specificity.calculate(':where')[0].toObject(), { a: 0, b: 0, c: 0 }); }); + + it(':is() = (0,0,0)', () => { + deepEqual(Specificity.calculate(':is()')[0].toObject(), { a: 0, b: 0, c: 0 }); + }); + it(':matches() = (0,0,0)', () => { + deepEqual(Specificity.calculate(':matches()')[0].toObject(), { a: 0, b: 0, c: 0 }); + }); + it(':any() = (0,0,0)', () => { + deepEqual(Specificity.calculate(':any()')[0].toObject(), { a: 0, b: 0, c: 0 }); + }); + it(':where() = (0,0,0)', () => { + deepEqual(Specificity.calculate(':where()')[0].toObject(), { a: 0, b: 0, c: 0 }); + }); }); describe('CSS :has() = Specificity of the most specific complex selector in its selector list argument', () => { @@ -231,7 +253,7 @@ describe('CALCULATE', () => { it(':host = (0,1,0)', () => { deepEqual(Specificity.calculate(':host')[0].toObject(), { a: 0, b: 1, c: 0 }); }); - it.skip(':host() = (0,1,0)', () => { + it(':host() = (0,1,0) & do not crash', () => { deepEqual(Specificity.calculate(':host()')[0].toObject(), { a: 0, b: 1, c: 0 }); }); it(':host(#foo.bar) = (1,2,0)', () => { @@ -240,7 +262,7 @@ describe('CALCULATE', () => { it(':host(#foo.bar invalid) = (1,2,0)', () => { deepEqual(Specificity.calculate(':host(#foo.bar invalid)')[0].toObject(), { a: 1, b: 2, c: 0 }); }); - it.skip(':host-context() = (0,1,0)', () => { + it(':host-context() = (0,1,0) & do not crash', () => { deepEqual(Specificity.calculate(':host-context()')[0].toObject(), { a: 0, b: 1, c: 0 }); }); it(':host-context(#foo.bar) = (1,2,0)', () => {