import { processExpression, createTransformContext, createSimpleExpression, createRoot, NodeTypes, SimpleExpressionNode, BindingMetadata } from '@vue/compiler-dom' import { SFCDescriptor } from './parse' import { rewriteDefault } from './rewriteDefault' import { ParserPlugin } from '@babel/parser' import postcss, { Root } from 'postcss' export const CSS_VARS_HELPER = `useCssVars` export const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g export function convertCssVarCasing(raw: string): string { return raw.replace(/([^\w-])/g, '_') } export function parseCssVars(sfc: SFCDescriptor): string[] { const vars: string[] = [] sfc.styles.forEach(style => { let match while ((match = cssVarRE.exec(style.content))) { vars.push(match[1] || match[2] || match[3]) } }) return vars } // for compileStyle export const cssVarsPlugin = postcss.plugin( 'vue-scoped', (id: any) => (root: Root) => { const shortId = id.replace(/^data-v-/, '') root.walkDecls(decl => { // rewrite CSS variables if (cssVarRE.test(decl.value)) { decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => { return `var(--${shortId}-${convertCssVarCasing($1 || $2 || $3)})` }) } }) } ) export function genCssVarsCode( vars: string[], bindings: BindingMetadata, id: string ) { const varsExp = `{\n ${vars .map(v => `"${id}-${convertCssVarCasing(v)}": (${v})`) .join(',\n ')}\n}` const exp = createSimpleExpression(varsExp, false) const context = createTransformContext(createRoot([]), { prefixIdentifiers: true, inline: true, bindingMetadata: bindings }) const transformed = processExpression(exp, context) const transformedString = transformed.type === NodeTypes.SIMPLE_EXPRESSION ? transformed.content : transformed.children .map(c => { return typeof c === 'string' ? c : (c as SimpleExpressionNode).content }) .join('') return `_${CSS_VARS_HELPER}(_ctx => (${transformedString}))` } //