Skip to content

Commit 553ef70

Browse files
committed
chore: add preserve fn
1 parent 0bbb4ac commit 553ef70

File tree

13 files changed

+343
-49
lines changed

13 files changed

+343
-49
lines changed

packages/core/src/css/plugins.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { PluginCreator } from 'postcss'
22
import defu from 'defu'
33
import parser from 'postcss-selector-parser'
4-
import { IClassGeneratorContextItem, ICssHandlerOptions } from '@/types'
4+
import { ICssHandlerOptions } from '@/types'
55
export type PostcssMangleTailwindcssPlugin = PluginCreator<ICssHandlerOptions>
66

77
const postcssPlugin = 'postcss-mangle-tailwindcss-plugin'

packages/core/src/ctx/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ export class Context {
3838
return this.preserveClassNamesSet.add(className)
3939
}
4040

41+
isPreserveFunction(calleeName: string) {
42+
// if (callee === undefined) {
43+
// return false
44+
// }
45+
return this.preserveFunctionSet.has(calleeName)
46+
}
47+
4148
mergeOptions(opts?: MangleUserConfig) {
4249
// 配置选项优先
4350
this.options = defu(this.options, opts)

packages/core/src/html/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { IHtmlHandlerOptions } from '../types'
44
import { makeRegex, splitCode } from '../shared'
55
// const { traverse } = await import('@parse5/tools')
66
export function htmlHandler(rawSource: string, options: IHtmlHandlerOptions) {
7-
const { replaceMap, classGenerator } = options
7+
const { replaceMap, ctx } = options
88
const fragment = parse(rawSource)
99
traverse(fragment, {
1010
element(node) {
@@ -15,7 +15,7 @@ export function htmlHandler(rawSource: string, options: IHtmlHandlerOptions) {
1515
})
1616
for (const v of array) {
1717
if (replaceMap.has(v)) {
18-
attribute.value = attribute.value.replace(makeRegex(v), classGenerator.generateClassName(v).name)
18+
attribute.value = attribute.value.replace(makeRegex(v), ctx.classGenerator.generateClassName(v).name)
1919
}
2020
}
2121
}

packages/core/src/js/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { makeRegex, splitCode } from '../shared'
55
import { isProd as isProduction } from '../env'
66
export { preProcessJs } from './pre'
77
export function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions) {
8-
const { replaceMap, classGenerator: clsGen, splitQuote = true } = options
9-
8+
const { replaceMap, ctx, splitQuote = true } = options
9+
const clsGen = ctx.classGenerator
1010
const array = splitCode(raw, {
1111
splitQuote
1212
})

packages/core/src/js/pre.ts

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import MagicString from 'magic-string'
44
import { splitCode } from '@tailwindcss-mangle/shared'
55
import { sort } from 'fast-sort'
66
import { jsStringEscape } from '@ast-core/escape'
7+
import { getStringLiteralCalleeName, getTemplateElementCalleeName } from './utils'
78
import type { Context } from '@/ctx'
89

910
interface Options {
@@ -13,20 +14,36 @@ interface Options {
1314
ctx: Context
1415
}
1516

16-
export function handleValue(options: { raw: string; node: babel.types.StringLiteral | babel.types.TemplateElement; offset: number; escape: boolean } & Options) {
17-
const { ctx, id, magicString, node, raw, replaceMap, offset = 0, escape = false } = options
17+
type HandleValueOptions = {
18+
raw: string
19+
path: babel.NodePath<babel.types.StringLiteral | babel.types.TemplateElement>
20+
offset: number
21+
escape: boolean
22+
preserve: boolean
23+
} & Options
24+
25+
export function handleValue(options: HandleValueOptions) {
26+
const { ctx, id, path, magicString, raw, replaceMap, offset = 0, escape = false, preserve = false } = options
27+
const node = path.node
1828
let value = raw
1929
const arr = sort(splitCode(value)).desc((x) => x.length)
2030

2131
for (const str of arr) {
2232
if (replaceMap.has(str)) {
2333
ctx.addToUsedBy(str, id)
34+
if (preserve) {
35+
ctx.addPreserveClass(str)
36+
}
37+
// replace
2438
const v = replaceMap.get(str)
2539
if (v) {
2640
value = value.replaceAll(str, v)
2741
}
2842
}
2943
}
44+
if (preserve) {
45+
return
46+
}
3047
if (typeof node.start === 'number' && typeof node.end === 'number' && value) {
3148
const start = node.start + offset
3249
const end = node.end - offset
@@ -43,32 +60,42 @@ export const plugin = declare((api, options: Options) => {
4360
visitor: {
4461
StringLiteral: {
4562
enter(p) {
46-
const node = p.node
47-
handleValue({
63+
const opts: HandleValueOptions = {
4864
ctx,
4965
id,
5066
magicString,
51-
node,
52-
raw: node.value,
67+
path: p,
68+
raw: p.node.value,
5369
replaceMap,
5470
offset: 1,
55-
escape: true
56-
})
71+
escape: true,
72+
preserve: false
73+
}
74+
const calleeName = getStringLiteralCalleeName(p)
75+
if (calleeName && ctx.isPreserveFunction(calleeName)) {
76+
opts.preserve = true
77+
}
78+
handleValue(opts)
5779
}
5880
},
5981
TemplateElement: {
6082
enter(p) {
61-
const node = p.node
62-
handleValue({
83+
const opts: HandleValueOptions = {
6384
ctx,
6485
id,
6586
magicString,
66-
node,
67-
raw: node.value.raw,
87+
path: p,
88+
raw: p.node.value.raw,
6889
replaceMap,
6990
offset: 0,
70-
escape: false
71-
})
91+
escape: false,
92+
preserve: false
93+
}
94+
const calleeName = getTemplateElementCalleeName(p)
95+
if (calleeName && ctx.isPreserveFunction(calleeName)) {
96+
opts.preserve = true
97+
}
98+
handleValue(opts)
7299
}
73100
}
74101
}

packages/core/src/js/utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import babel from '@babel/core'
2+
// const t = babel.types
3+
export function getStringLiteralCalleeName(path: babel.NodePath<babel.types.StringLiteral>) {
4+
if (path.parentPath.isCallExpression()) {
5+
const callee = path.parentPath.get('callee')
6+
if (callee.isIdentifier()) {
7+
return callee.node.name
8+
}
9+
}
10+
}
11+
12+
export function getTemplateElementCalleeName(path: babel.NodePath<babel.types.TemplateElement>) {
13+
if (path.parentPath.isTemplateLiteral()) {
14+
const pp = path.parentPath
15+
if (pp.parentPath.isCallExpression()) {
16+
const callee = pp.parentPath.get('callee')
17+
if (callee.isIdentifier()) {
18+
return callee.node.name
19+
}
20+
}
21+
}
22+
}

packages/core/src/types.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import type { ClassGenerator } from './shared'
2-
1+
import type { Context } from './ctx'
32
export interface IClassGeneratorContextItem {
43
name: string
54
usedBy: string[]
@@ -16,8 +15,8 @@ export interface IClassGeneratorOptions {
1615
}
1716

1817
export interface IHandlerOptions {
19-
classGenerator: ClassGenerator
2018
replaceMap: Map<string, string>
19+
ctx: Context
2120
}
2221

2322
export interface IHtmlHandlerOptions extends IHandlerOptions {}

packages/core/test/__snapshots__/js.test.ts.snap

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,86 @@ exports[`js handler > nextjs server side mangle 1`] = `
252252
})();"
253253
`;
254254
255+
exports[`js handler > preserve-fn-case0.js case 0 1`] = `
256+
"import { clsx } from \\"clsx\\";
257+
import { twMerge } from \\"tailwind-merge\\";
258+
259+
export function cn(...inputs) {
260+
return twMerge(clsx(inputs));
261+
}
262+
263+
cn('w-10 h-10 b and a')
264+
265+
cn(\`w-2 h-2 bg-red-600 and bg-red-600/50\`)
266+
267+
twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')"
268+
`;
269+
270+
exports[`js handler > preserve-fn-case0.js case 1 1`] = `
271+
"import { clsx } from \\"clsx\\";
272+
import { twMerge } from \\"tailwind-merge\\";
273+
274+
export function cn(...inputs) {
275+
return twMerge(clsx(inputs));
276+
}
277+
278+
cn('w-10 h-10 bg-red-500 and bg-red-500/50')
279+
280+
cn(\`w-2 h-2 bg-red-600 and bg-red-600/50\`)
281+
282+
twMerge('e f g and h')"
283+
`;
284+
285+
exports[`js handler > preserve-fn-case0.js case 1 2`] = `
286+
{
287+
"bg-red-400": "g",
288+
"bg-red-400/50": "h",
289+
"h-1": "f",
290+
"w-1": "e",
291+
}
292+
`;
293+
294+
exports[`js handler > preserve-fn-case0.js case 2 1`] = `
295+
"import { clsx } from \\"clsx\\";
296+
import { twMerge } from \\"tailwind-merge\\";
297+
298+
export function cn(...inputs) {
299+
return twMerge(clsx(inputs));
300+
}
301+
302+
cn('w-10 h-10 b and a')
303+
304+
cn(\`c d bg-red-600 and bg-red-600/50\`)
305+
306+
twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')"
307+
`;
308+
309+
exports[`js handler > preserve-fn-case0.js case 2 2`] = `
310+
Map {
311+
"bg-red-500/50" => "a",
312+
"bg-red-500" => "b",
313+
"w-2" => "c",
314+
"h-2" => "d",
315+
}
316+
`;
317+
318+
exports[`js handler > preserve-fn-case0.js case 3 1`] = `
319+
"import { clsx } from \\"clsx\\";
320+
import { twMerge } from \\"tailwind-merge\\";
321+
322+
export function cn(...inputs) {
323+
return twMerge(clsx(inputs));
324+
}
325+
326+
cn('w-10 h-10 bg-red-500 and bg-red-500/50')
327+
328+
cn(\`w-2 h-2 bg-red-600 and bg-red-600/50\`)
329+
330+
twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')"
331+
`;
332+
333+
exports[`js handler > preserve-fn-case0.js case 3 2`] = `Map {}`;
334+
255335
exports[`js handler > trailing slash case 0 1`] = `"document.getElementById(\\"#app\\").classList.add(\\"tw-a tw-b\\");"`;
256336
257337
exports[`js handler > trailing slash case 1 1`] = `"document.querySelector(\\"#app\\").classList.add(\\"tw-a tw-b\\");"`;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { clsx } from "clsx";
2+
import { twMerge } from "tailwind-merge";
3+
4+
export function cn(...inputs) {
5+
return twMerge(clsx(inputs));
6+
}
7+
8+
cn('w-10 h-10 bg-red-500 and bg-red-500/50')
9+
10+
cn(`w-2 h-2 bg-red-600 and bg-red-600/50`)
11+
12+
twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { type ClassValue, clsx } from "clsx";
2+
import { twMerge } from "tailwind-merge";
3+
4+
export function cn(...inputs: ClassValue[]) {
5+
return twMerge(clsx(inputs));
6+
}
7+
8+
cn('w-10 h-10 bg-red-500 and bg-red-500/50')
9+
10+
cn(`w-2 h-2 bg-red-600 and bg-red-600/50`)
11+
12+
twMerge('w-1 h-1 bg-red-400 and bg-red-400/50')

0 commit comments

Comments
 (0)