babel-plugin-styled-components-px2vw
Version:
Babel plugin for convert px to vw units of styled-components
85 lines (79 loc) • 3.04 kB
text/typescript
import postcss from 'postcss';
import memoize from 'memoizerific';
import px2vw from 'postcss-px-to-viewport'; //TODO: upgrade to 8 version wait postcss-px-to-viewport support
import { IPx2VwOptions } from '../types/options';
import configuration from './configuration';
const FAKE_OPENING_WRAPPER = `styled-fake-wrapper/* start of styled-fake-wrapper */{
`;
const FAKE_CLOSING_WRAPPER = `
}/* end of styled-fake-wrapper */`;
const FAKE_RULE = '/* start of styled-fake-rule */padding:/* end of styled-fake-rule */';
const PAIR_REG = /[\s\w-]+:([\s\w.-])+/;
// const PAIR_REG = /[\s\w-]+:([\s-\d]+px)+/;
const PX_UNIT_REG = new RegExp(`([\\s-\\d]+${configuration.config.unitToConvert})+`); //;
const SPLIT_SEPARATORS = [';', '\n', '{', '}'];
const errorTokenMap = new Map(); // a map data prevent infinite loop
function process(css: string): string {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { tags, ...others } = configuration.config;
const options: IPx2VwOptions = {
...others,
};
return postcss([px2vw(options)]).process(css, {
// syntax: scss,
}).css;
}
function replaceWithRecord(cssText: string): string {
const { unitToConvert } = configuration.config;
try {
if (PAIR_REG.test(cssText)) {
const replaced = process(`${FAKE_OPENING_WRAPPER}${cssText}${FAKE_CLOSING_WRAPPER}`);
/* istanbul ignore next */
if (errorTokenMap.has(cssText)) {
errorTokenMap.delete(cssText);
}
return replaced.replace(FAKE_OPENING_WRAPPER, '').replace(FAKE_CLOSING_WRAPPER, '');
} else if (PX_UNIT_REG.test(cssText)) {
const replaced = process(`${FAKE_RULE}${cssText}`);
/* istanbul ignore next */
if (errorTokenMap.has(cssText)) {
errorTokenMap.delete(cssText);
}
return replaced.replace(FAKE_RULE, '');
} else {
/* istanbul ignore next */
if (errorTokenMap.has(cssText)) {
errorTokenMap.delete(cssText);
}
return cssText;
}
} catch (ignored) {
let tempResults: string[] = [];
let cssStr = cssText;
SPLIT_SEPARATORS.forEach((separator) => {
const tokens = cssStr.split(separator);
for (const token of tokens) {
const tokenRemoveComments = token.replace(/\s*(?<!(\/\*.*|[::]))\/\/.*$/gm, ''); // remove single-line comments
// TODO:consider into propList option
if (
PAIR_REG.test(tokenRemoveComments) &&
tokenRemoveComments.includes(unitToConvert) &&
!errorTokenMap.get(tokenRemoveComments) &&
!!token.trim()
) {
errorTokenMap.set(tokenRemoveComments, true);
tempResults.push(replace(tokenRemoveComments));
} else {
tempResults.push(token);
}
}
cssStr = tempResults.join(separator);
tempResults = [];
});
return cssStr;
}
}
export const replace = memoize(10)(function (cssText: string): string {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return replaceWithRecord(cssText);
});