mirror of https://github.com/vuejs/vitepress
BREAKING CHANGE: `includeFiles` option in `postcssIsolateStyles` now defaults to `[/vp-doc\.css/, /base\.css/]` You can remove explicit `includeFiles` if you were using it just to run it on `vp-doc.css`. To revert back to older behavior pass `includeFiles: [/base\.css/]`. The underlying implementation is changed and `transform` and `exclude` options are no longer supported. Use `postcss-prefix-selector` directly if you've advanced use cases.pull/4910/head
parent
991c780a07
commit
0944777893
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,38 @@
|
||||
import postcssPrefixSelector from 'postcss-prefix-selector'
|
||||
import type { Plugin } from 'postcss'
|
||||
import selectorParser from 'postcss-selector-parser'
|
||||
|
||||
export function postcssIsolateStyles(
|
||||
options: Parameters<typeof postcssPrefixSelector>[0] = {}
|
||||
): ReturnType<typeof postcssPrefixSelector> {
|
||||
return postcssPrefixSelector({
|
||||
prefix: ':not(:where(.vp-raw, .vp-raw *))',
|
||||
includeFiles: [/base\.css/],
|
||||
transform(prefix, _selector) {
|
||||
// split selector from its pseudo part if the trailing colon is not escaped
|
||||
const [selector, pseudo] = splitSelectorPseudo(_selector)
|
||||
return selector + prefix + pseudo
|
||||
},
|
||||
...options
|
||||
})
|
||||
type Options = {
|
||||
includeFiles?: RegExp[]
|
||||
ignoreFiles?: RegExp[]
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
export function splitSelectorPseudo(selector: string): [string, string] {
|
||||
const [base, pseudo = ''] = selector.split(/(?<!\\)(:\S*)$/)
|
||||
return [base, pseudo]
|
||||
export function postcssIsolateStyles({
|
||||
includeFiles = [/vp-doc\.css/, /base\.css/],
|
||||
ignoreFiles,
|
||||
prefix = ':not(:where(.vp-raw, .vp-raw *))'
|
||||
}: Options = {}): Plugin {
|
||||
const prefixNodes = selectorParser().astSync(prefix).first.nodes
|
||||
|
||||
return /* prettier-ignore */ {
|
||||
postcssPlugin: 'postcss-isolate-styles',
|
||||
Once(root) {
|
||||
const file = root.source?.input.file
|
||||
if (file && includeFiles?.length && !includeFiles.some((re) => re.test(file))) return
|
||||
if (file && ignoreFiles?.length && ignoreFiles.some((re) => re.test(file))) return
|
||||
|
||||
root.walkRules((rule) => {
|
||||
if (!rule.selector || rule.selector.includes(prefix)) return
|
||||
if (rule.parent?.type === 'atrule' && /\bkeyframes$/i.test(rule.parent.name)) return
|
||||
|
||||
rule.selector = selectorParser((selectors) => {
|
||||
selectors.each((sel) => {
|
||||
if (!sel.nodes.length) return
|
||||
const insertionIndex = sel.nodes.findLastIndex((n) => n.type !== 'pseudo') + 1
|
||||
sel.nodes.splice(insertionIndex, 0, ...prefixNodes.map((n) => n.clone() as any))
|
||||
})
|
||||
}).processSync(rule.selector)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue