@lwc/style-compiler
Version:
Transform style sheet to be consumed by the LWC engine
72 lines (60 loc) • 3.1 kB
text/typescript
/*
* Copyright (c) 2018, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import postcss, { Root, Result } from 'postcss';
import postCssSelector from 'postcss-selector-parser';
import { Processor } from 'postcss-selector-parser';
import validateCustomProperties from './custom-properties/validate';
import validateIdSelectors from './no-id-selectors/validate';
import transformImport from './css-import/transform';
import transformSelectorScoping, { SelectorScopingConfig } from './selector-scoping/transform';
import transformCustomProperties from './custom-properties/transform';
export type VarTransformer = (name: string, fallback: string) => string;
export interface PluginConfig {
customProperties?: {
allowDefinition?: boolean;
collectVarFunctions?: boolean;
};
minify?: boolean;
}
function selectorProcessorFactory(config: PluginConfig, transformConfig: SelectorScopingConfig) {
return postCssSelector(root => {
validateIdSelectors(root);
transformSelectorScoping(root, transformConfig);
}) as Processor;
}
export default postcss.plugin('postcss-plugin-lwc', (pluginConfig: PluginConfig) => {
// We need 2 types of selectors processors, since transforming the :host selector make the selector
// unusable when used in the context of the native shadow and vice-versa.
const nativeShadowSelectorProcessor = selectorProcessorFactory(pluginConfig, { transformHost: false });
const fakeShadowSelectorProcessor = selectorProcessorFactory(pluginConfig, { transformHost: true });
return (root: Root, result: Result) => {
const { customProperties } = pluginConfig;
transformImport(root, result);
if (!customProperties || !customProperties.allowDefinition) {
validateCustomProperties(root);
}
transformCustomProperties(root, result);
root.walkRules(rule => {
// Let transform the selector with the 2 processors.
const fakeShadowSelector = fakeShadowSelectorProcessor.processSync(rule);
const nativeShadowSelector = nativeShadowSelectorProcessor.processSync(rule);
rule.selector = fakeShadowSelector;
// If the resulting selector are different it means that the selector use the :host selector. In
// this case we need to duplicate the CSS rule and assign the other selector.
if (fakeShadowSelector !== nativeShadowSelector) {
// The cloned selector is inserted before the currently processed selector to avoid processing
// again the cloned selector.
const currentRule: any = rule;
const clonedRule: any = rule.cloneBefore();
clonedRule.selector = nativeShadowSelector;
// Safe a reference to each other
clonedRule._isHostNative = true;
currentRule._isFakeNative = true;
}
});
};
});