-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: use smarter class separation, fixes #46
- Loading branch information
Showing
5 changed files
with
152 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { loadStyleDefinitions } from '../../src'; | ||
import { getCriticalStyles } from '../../src/getCSS'; | ||
|
||
describe('missing styles', () => { | ||
it('result should contain full fill value', async () => { | ||
const styles = loadStyleDefinitions( | ||
() => ['test.css'], | ||
() => ` | ||
.-lottie-player svg path[fill="rgb(255,255,255)"] { | ||
fill: var(--color-background) | ||
} | ||
` | ||
); | ||
await styles; | ||
|
||
expect(styles.ast['test.css'].selectors).toMatchInlineSnapshot(` | ||
Array [ | ||
Object { | ||
"declaration": 1, | ||
"hash": ".-lottie-player svg path[fill=\\"rgb(255,255,255)\\"]1noj2ak-1etm6d20", | ||
"media": Array [], | ||
"parents": Array [ | ||
"-lottie-player", | ||
], | ||
"pieces": Array [ | ||
"-lottie-player", | ||
], | ||
"postfix": "svg path[fill=\\"rgb(255,255,255)\\"]", | ||
"selector": ".-lottie-player svg path[fill=\\"rgb(255,255,255)\\"]", | ||
}, | ||
] | ||
`); | ||
|
||
const extracted = getCriticalStyles( | ||
'<div class="-lottie-player"><svg><path fill="rgb(255,255,255)"></path></svg></div>', | ||
styles | ||
); | ||
|
||
expect(extracted).toMatchInlineSnapshot(` | ||
"<style type=\\"text/css\\" data-used-styles=\\"test.css\\">.-lottie-player svg path[fill=\\"rgb(255,255,255)\\"] { fill: var(--color-background); } | ||
</style>" | ||
`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { splitSelector } from '../split-selectors'; | ||
|
||
describe('split selectors', () => { | ||
it('simple', () => { | ||
expect(splitSelector('.a')).toEqual(['.a']); | ||
expect(splitSelector('.a,.b')).toEqual(['.a', '.b']); | ||
expect(splitSelector('.a:before,:after')).toEqual(['.a:before', ':after']); | ||
}); | ||
|
||
it('complex', () => { | ||
expect(splitSelector('a ~ span,b')).toEqual(['a ~ span', 'b']); | ||
expect(splitSelector("a#item p[alt^='test'],.body.test")).toEqual(["a#item p[alt^='test']", '.body.test']); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/** | ||
* @fileOverview inspired by https://github.com/perry-mitchell/css-selector-splitter/tree/master | ||
*/ | ||
|
||
const BLOCKS: Record<string, string> = { | ||
'(': ')', | ||
'[': ']', | ||
}; | ||
|
||
const QUOTES: Record<string, string> = { | ||
'"': '"', | ||
"'": "'", | ||
}; | ||
|
||
const FINALIZERS: Record<string, string> = { | ||
')': '(', | ||
']': '[', | ||
}; | ||
|
||
const SPLIT_ON: Record<string, string> = { | ||
',': ',', | ||
}; | ||
|
||
export const splitSelector = (selector: string): string[] => { | ||
const selectors: string[] = []; | ||
|
||
const stack: string[] = []; | ||
const joiners: string[] = []; | ||
let currentSelector = ''; | ||
|
||
for (let i = 0; i < selector.length; i += 1) { | ||
const char = selector[i]; | ||
|
||
if (BLOCKS[char] || QUOTES[char]) { | ||
if (stack.length === 0) { | ||
stack.push(char); | ||
} else { | ||
const lastBrace = stack[stack.length - 1]; | ||
|
||
if (QUOTES[lastBrace]) { | ||
// within quotes | ||
if (char === lastBrace) { | ||
// closing quote | ||
stack.pop(); | ||
} | ||
} else { | ||
// inside brackets or square brackets | ||
stack.push(char); | ||
} | ||
} | ||
|
||
currentSelector += char; | ||
} else if (FINALIZERS.hasOwnProperty(char)) { | ||
const lastBrace = stack[stack.length - 1]; | ||
const matchingOpener = FINALIZERS[char]; | ||
|
||
if (lastBrace === matchingOpener) { | ||
stack.pop(); | ||
} | ||
|
||
currentSelector += char; | ||
} else if (SPLIT_ON[char]) { | ||
if (!stack.length) { | ||
// we're not inside another block, so we can split using the comma/splitter | ||
const lastJoiner = joiners[joiners.length - 1]; | ||
|
||
if (lastJoiner === ' ' && currentSelector.length <= 0) { | ||
// we just split by a space, but there seems to be another split character, so use | ||
// this new one instead of the previous space | ||
joiners[joiners.length - 1] = char; | ||
} else if (currentSelector.length <= 0) { | ||
// skip this character, as it's just padding | ||
} else { | ||
// split by this character | ||
const newLength = selectors.push(currentSelector); | ||
joiners[newLength - 1] = char; | ||
currentSelector = ''; | ||
} | ||
} else { | ||
// we're inside another block, so ignore the comma/splitter | ||
currentSelector += char; | ||
} | ||
} else { | ||
// just add this character | ||
currentSelector += char; | ||
} | ||
} | ||
|
||
selectors.push(currentSelector); | ||
|
||
return selectors.map((selector) => selector.trim()).filter((cssSelector) => cssSelector.length > 0); | ||
}; |