Skip to content

Commit

Permalink
wip: css name transformer postcss plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
daief committed Jun 24, 2023
1 parent d922dc0 commit 9af89fc
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 57 deletions.
91 changes: 44 additions & 47 deletions packages/develop/__tests__/classname-plugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ts from 'typescript';
import {
createClassnameTransformer,
clsUnique,
clsUniquePrefix,
postcssDvClsTransformer,
convertKeyFramesName,
} from '../src/build/classname-plugin';
Expand All @@ -12,59 +12,56 @@ describe('classname-plugin', () => {
const compile = (code: string) =>
postcss([postcssDvClsTransformer()]).process(code, { from: undefined });

const classCodes = [`.dv-btn {}`, `.dv-a, .dv-a .dv-b {}`];
const classCodesResult = classCodes.map((it) =>
it.replace(/\.dv-/g, '.' + clsUnique + '-'),
);

const keyframesCodes = [
`@keyframes a {}`,
`a { animation-name: aaa; }`,
`a { animation: bbb 1s, ccc 2s; }`,
`a { animation-name: var(--a); }`,
];
const keyframesCodesResults = [
`@keyframes ${convertKeyFramesName('a')} {}`,
`a { animation-name: ${convertKeyFramesName('aaa')}; }`,
`a { animation: ${convertKeyFramesName('bbb')} 1s, ${convertKeyFramesName(
'ccc',
)} 2s; }`,
`a { animation-name: var(--a); }`,
const its = [
[`.dv-btn {}`],
[
`.a, .aa .dv-b {}`,
`.${clsUniquePrefix}a, .${clsUniquePrefix}aa .dv-b {}`,
],
[`@keyframes a {}`, `@keyframes ${clsUniquePrefix}a {}`],
[
`a { animation-name: aaa; }`,
`a { animation-name: ${clsUniquePrefix}aaa; }`,
],
[
`a { animation: bbb 1s, ccc 2s; }`,
`a { animation: ${clsUniquePrefix}bbb 1s, ${clsUniquePrefix}ccc 2s; }`,
],
[`a { animation-name: var(--a); }`, `a { animation-name: var(--a); }`],
];

const codes = [...classCodes, ...keyframesCodes];
const results = [...classCodesResult, ...keyframesCodesResults];
for (let index = 0; index < its.length; index++) {
let [code, result] = its[index];
result = result ?? code;

for (let index = 0; index < codes.length; index++) {
const code = codes[index];
const result = await compile(code);
expect(result.css.trim()).toEqual(results[index]);
const actualResult = await compile(code);
expect(actualResult.css.trim()).toEqual(result);
}
});

it('ts-transformer', () => {
const compile = (code: string) =>
ts.transpileModule(code, {
compilerOptions: {
target: ts.ScriptTarget.ES2015,
},
transformers: {
before: [createClassnameTransformer],
},
});
// it('ts-transformer', () => {
// const compile = (code: string) =>
// ts.transpileModule(code, {
// compilerOptions: {
// target: ts.ScriptTarget.ES2015,
// },
// transformers: {
// before: [createClassnameTransformer],
// },
// });

const codes = ['__c`dv-btn`', "__c`dv-btn-${'primary'}`"];
const results = codes.map(
(it) => it.replace('__c', '').replace('`dv', '`' + clsUnique) + ';',
);
// const codes = ['__c`dv-btn`', "__c`dv-btn-${'primary'}`"];
// const results = codes.map(
// (it) => it.replace('__c', '').replace('`dv', '`' + clsUnique) + ';',
// );

codes.forEach((code, i) => {
const result = compile(code);
expect(result.outputText.trim()).toEqual(results[i]);
});
// codes.forEach((code, i) => {
// const result = compile(code);
// expect(result.outputText.trim()).toEqual(results[i]);
// });

expect(() => compile('__c``')).toThrow();
expect(() => compile('__c`a`')).toThrow();
expect(() => compile('__c`dva`')).toThrow();
});
// expect(() => compile('__c``')).toThrow();
// expect(() => compile('__c`a`')).toThrow();
// expect(() => compile('__c`dva`')).toThrow();
// });
});
36 changes: 26 additions & 10 deletions packages/develop/src/build/classname-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const clsUnique =
.digest('base64url')
.slice(0, 6);

export const clsUniquePrefix = clsUnique + '-';

/**
* __c 包裹的类名添加标识
* @param context
Expand Down Expand Up @@ -73,37 +75,51 @@ export const createClassnameTransformerFactory = (program: ts.Program) => {
return createClassnameTransformer;
};

export const convertClsName = (name: string) =>
name.replace(/\.dv-/g, '.' + clsUnique + '-');
export const convertKeyFramesName = (name: string) => clsUnique + '-' + name;
export const convertKeyFramesName = (name: string) => clsUniquePrefix + name;

/**
* classname 和 keyframes name 添加 hash 前缀
* - 暂时地:dv- 开头的类忽略
* @returns
*/
export const postcssDvClsTransformer = (): Plugin => {
const cache: Record<string, boolean> = {};
return {
postcssPlugin: 'postcssDvClsTransformer',
Rule(rule) {
rule.selector = convertClsName(rule.selector);
if (cache[rule.selector]) return;

rule.selector = rule.selector.replace(/\.(dv-)?/g, (substr) => {
if (substr === '.dv-') return substr; // TODO rm
return '.' + clsUniquePrefix;
});
cache[rule.selector] = true;
},
AtRuleExit(atRule) {
if (atRule.name === 'keyframes' && !atRule.params.startsWith(clsUnique)) {
atRule.params = convertKeyFramesName(atRule.params);
}
if (atRule.name !== 'keyframes') return;
if (atRule.params.startsWith(clsUnique)) return;

if (atRule.params.startsWith('dv-')) return; // TODO rm

atRule.params = convertKeyFramesName(atRule.params);
},
Declaration: {
['animation-name']: (decl) => {
if (!decl.value.startsWith(clsUnique)) {
decl.value = convertKeyFramesName(decl.value);
}
if (decl.value.startsWith(clsUnique)) return;
if (decl.value.startsWith('var(')) return;
if (decl.value.startsWith('dv-')) return; // TODO rm

decl.value = convertKeyFramesName(decl.value);
},

animation: (decl) => {
const parsed = parse(decl.value);
const names = parsed.map((it) => it.name);
names.forEach((name) => {
if (name.startsWith(clsUnique)) return;
if (decl.value.startsWith('var(')) return;
if (decl.value.startsWith('dv-')) return; // TODO rm

decl.value = decl.value.replace(name, convertKeyFramesName(name));
});
},
Expand Down

0 comments on commit 9af89fc

Please sign in to comment.