@tailwindcss-mangle/core 2.3.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,7 +6,6 @@ const process = require('node:process');
6
6
  const shared = require('@tailwindcss-mangle/shared');
7
7
  const config = require('@tailwindcss-mangle/config');
8
8
  const fastSort = require('fast-sort');
9
- const micromatch = require('micromatch');
10
9
  const postcss = require('postcss');
11
10
  const parser = require('postcss-selector-parser');
12
11
  const htmlparser2 = require('htmlparser2');
@@ -14,13 +13,11 @@ const MagicString = require('magic-string');
14
13
  const escape = require('@ast-core/escape');
15
14
  const _babelTraverse = require('@babel/traverse');
16
15
  const parser$1 = require('@babel/parser');
17
- const compilerSfc = require('@vue/compiler-sfc');
18
16
 
19
17
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
20
18
 
21
19
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
22
20
  const process__default = /*#__PURE__*/_interopDefaultCompat(process);
23
- const micromatch__default = /*#__PURE__*/_interopDefaultCompat(micromatch);
24
21
  const postcss__default = /*#__PURE__*/_interopDefaultCompat(postcss);
25
22
  const parser__default = /*#__PURE__*/_interopDefaultCompat(parser);
26
23
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
@@ -82,23 +79,12 @@ function createDefu(merger) {
82
79
  }
83
80
  const defu = createDefu();
84
81
 
85
- const { isMatch } = micromatch__default;
86
82
  function escapeStringRegexp(str) {
87
83
  if (typeof str !== "string") {
88
84
  throw new TypeError("Expected a string");
89
85
  }
90
86
  return str.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&").replaceAll("-", "\\x2d");
91
87
  }
92
- function createGlobMatcher(pattern, fallbackValue = false) {
93
- if (pattern === void 0) {
94
- return function() {
95
- return fallbackValue;
96
- };
97
- }
98
- return function(file) {
99
- return isMatch(file, pattern);
100
- };
101
- }
102
88
 
103
89
  var __defProp = Object.defineProperty;
104
90
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -109,8 +95,6 @@ var __publicField = (obj, key, value) => {
109
95
  class Context {
110
96
  constructor() {
111
97
  __publicField(this, "options");
112
- __publicField(this, "includeMatcher");
113
- __publicField(this, "excludeMatcher");
114
98
  __publicField(this, "replaceMap");
115
99
  __publicField(this, "classSet");
116
100
  __publicField(this, "classGenerator");
@@ -120,8 +104,6 @@ class Context {
120
104
  this.options = {};
121
105
  this.classSet = /* @__PURE__ */ new Set();
122
106
  this.replaceMap = /* @__PURE__ */ new Map();
123
- this.includeMatcher = () => true;
124
- this.excludeMatcher = () => false;
125
107
  this.classGenerator = new shared.ClassGenerator();
126
108
  this.preserveFunctionSet = /* @__PURE__ */ new Set();
127
109
  this.preserveClassNamesSet = /* @__PURE__ */ new Set();
@@ -138,17 +120,12 @@ class Context {
138
120
  }
139
121
  mergeOptions(...opts) {
140
122
  this.options = defu(this.options, ...opts);
141
- this.includeMatcher = createGlobMatcher(this.options.include, true);
142
- this.excludeMatcher = createGlobMatcher(this.options.exclude, false);
143
123
  this.classGenerator = new shared.ClassGenerator(this.options.classGenerator);
144
124
  this.preserveFunctionSet = new Set(this.options?.preserveFunction ?? []);
145
125
  this.preserveFunctionRegexs = [...this.preserveFunctionSet.values()].map((x) => {
146
126
  return new RegExp(`${escapeStringRegexp(x)}\\(([^)]*)\\)`, "g");
147
127
  });
148
128
  }
149
- isInclude(file) {
150
- return this.includeMatcher(file) && !this.excludeMatcher(file);
151
- }
152
129
  currentMangleClassFilter(className) {
153
130
  return (this.options.mangleClassFilter ?? shared.defaultMangleClassFilter)(className);
154
131
  }
@@ -159,6 +136,9 @@ class Context {
159
136
  return this.replaceMap;
160
137
  }
161
138
  addToUsedBy(key, file) {
139
+ if (!file) {
140
+ return;
141
+ }
162
142
  const hit = this.classGenerator.newClassMap[key];
163
143
  if (hit) {
164
144
  hit.usedBy.add(file);
@@ -175,6 +155,12 @@ class Context {
175
155
  async initConfig(opts = {}) {
176
156
  const { cwd, classList: _classList, mangleOptions } = opts;
177
157
  const { config: config$1, cwd: configCwd } = await config.getConfig(cwd);
158
+ if (mangleOptions?.classMapOutput === true) {
159
+ mangleOptions.classMapOutput = config$1.mangle?.classMapOutput;
160
+ if (typeof mangleOptions.classMapOutput === "object") {
161
+ mangleOptions.classMapOutput.enable = true;
162
+ }
163
+ }
178
164
  this.mergeOptions(mangleOptions, config$1?.mangle);
179
165
  if (_classList) {
180
166
  this.loadClassSet(_classList);
@@ -197,7 +183,25 @@ class Context {
197
183
  }
198
184
  return config$1;
199
185
  }
200
- // ["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
186
+ async dump() {
187
+ try {
188
+ const arr = Object.entries(this.classGenerator.newClassMap).map((x) => {
189
+ return {
190
+ before: x[0],
191
+ after: x[1].name,
192
+ usedBy: Array.from(x[1].usedBy)
193
+ };
194
+ });
195
+ if (typeof this.options.classMapOutput === "function") {
196
+ await this.options.classMapOutput(arr);
197
+ } else if (typeof this.options.classMapOutput === "object" && this.options.classMapOutput.enable && this.options.classMapOutput.filename) {
198
+ fs__default.mkdirSync(node_path.dirname(this.options.classMapOutput.filename), { recursive: true });
199
+ fs__default.writeFileSync(this.options.classMapOutput.filename, JSON.stringify(arr, null, 2));
200
+ }
201
+ } catch (error) {
202
+ console.error(`[tailwindcss-mangle]: ${error}`);
203
+ }
204
+ }
201
205
  }
202
206
 
203
207
  const postcssPlugin = "postcss-mangle-tailwindcss-plugin";
@@ -214,7 +218,7 @@ function isVueScoped(s) {
214
218
  return false;
215
219
  }
216
220
  const transformSelectorPostcssPlugin = function(options) {
217
- const { ignoreVueScoped, ctx } = defu(options, {
221
+ const { ignoreVueScoped, ctx, id } = defu(options, {
218
222
  ignoreVueScoped: true
219
223
  });
220
224
  const replaceMap = ctx.replaceMap;
@@ -247,211 +251,58 @@ const transformSelectorPostcssPlugin = function(options) {
247
251
  };
248
252
  transformSelectorPostcssPlugin.postcss = true;
249
253
 
250
- function cssHandler(rawSource, options) {
254
+ async function cssHandler(rawSource, options) {
251
255
  const acceptedPlugins = [transformSelectorPostcssPlugin(options)];
252
- const { file } = options;
253
- return postcss__default(acceptedPlugins).process(rawSource, {
254
- from: file,
255
- to: file
256
+ const { id } = options;
257
+ const { css: code, map } = await postcss__default(acceptedPlugins).process(rawSource, {
258
+ from: id,
259
+ to: id
256
260
  });
261
+ return {
262
+ code,
263
+ // @ts-ignore
264
+ map
265
+ };
257
266
  }
258
267
 
259
- function _interopDefaultCompat$1(e) {
260
- return e && typeof e === "object" && "default" in e ? e.default : e;
261
- }
262
- const traverse = _interopDefaultCompat$1(_babelTraverse__default);
263
-
264
- function between(x, min, max, included = false) {
265
- if (typeof x !== "number") {
266
- return false;
267
- }
268
- return included ? x >= min && x <= max : x > min && x < max;
269
- }
270
-
271
- function handleValue$1(options) {
272
- const { ctx, id, path, magicString, raw, offset = 0, escape: escape$1 = false, markedArray } = options;
273
- const { replaceMap } = ctx;
274
- const node = path.node;
275
- let value = raw;
276
- for (const [s, e] of markedArray) {
277
- if (between(node.start, s, e) || between(node.end, s, e)) {
278
- return;
279
- }
280
- }
281
- const arr = fastSort.sort(shared.splitCode(value)).desc((x) => x.length);
282
- for (const str of arr) {
283
- if (replaceMap.has(str)) {
284
- ctx.addToUsedBy(str, id);
285
- const v = replaceMap.get(str);
286
- if (v && typeof v === "string") {
287
- value = value.replaceAll(str, v);
288
- }
289
- }
290
- }
291
- if (typeof node.start === "number" && typeof node.end === "number" && value) {
292
- const start = node.start + offset;
293
- const end = node.end - offset;
294
- if (start < end) {
295
- magicString.update(start, end, escape$1 ? escape.jsStringEscape(value) : value);
296
- }
297
- }
298
- }
299
- function preProcessJs(options) {
300
- const { code, id, ctx } = options;
301
- const { replaceMap } = ctx;
302
- const magicString = typeof code === "string" ? new MagicString__default(code) : code;
303
- let ast;
304
- try {
305
- const file = parser$1.parse(magicString.original, {
306
- sourceType: "unambiguous",
307
- plugins: ["typescript", "jsx"]
308
- });
309
- if (file) {
310
- ast = file;
311
- } else {
312
- return code.toString();
313
- }
314
- } catch {
315
- return code.toString();
316
- }
317
- const markedArray = [];
318
- traverse(ast, {
319
- CallExpression: {
320
- enter(p) {
321
- const callee = p.get("callee");
322
- if (callee.isIdentifier() && ctx.isPreserveFunction(callee.node.name)) {
323
- if (p.node.start && p.node.end) {
324
- markedArray.push([p.node.start, p.node.end]);
268
+ function htmlHandler(raw, options) {
269
+ const { ctx, id } = options;
270
+ const { replaceMap, classGenerator } = ctx;
271
+ const ms = typeof raw === "string" ? new MagicString__default(raw) : raw;
272
+ const parser = new htmlparser2.Parser({
273
+ onattribute(name, value) {
274
+ if (name === "class") {
275
+ let needUpdate = false;
276
+ const arr = shared.splitCode(value, {
277
+ splitQuote: false
278
+ });
279
+ let rawValue = value;
280
+ for (const v of arr) {
281
+ if (replaceMap.has(v)) {
282
+ const gen = classGenerator.generateClassName(v);
283
+ rawValue = rawValue.replace(shared.makeRegex(v), gen.name);
284
+ ctx.addToUsedBy(v, id);
285
+ needUpdate = true;
325
286
  }
326
- p.traverse({
327
- StringLiteral: {
328
- enter(path) {
329
- const node = path.node;
330
- const value = node.value;
331
- const arr = fastSort.sort(shared.splitCode(value)).desc((x) => x.length);
332
- for (const str of arr) {
333
- if (replaceMap.has(str)) {
334
- ctx.addPreserveClass(str);
335
- }
336
- }
337
- }
338
- },
339
- TemplateElement: {
340
- enter(path) {
341
- const node = path.node;
342
- const value = node.value.raw;
343
- const arr = fastSort.sort(shared.splitCode(value)).desc((x) => x.length);
344
- for (const str of arr) {
345
- if (replaceMap.has(str)) {
346
- ctx.addPreserveClass(str);
347
- }
348
- }
349
- }
350
- }
351
- });
352
287
  }
353
- }
354
- },
355
- StringLiteral: {
356
- exit(p) {
357
- handleValue$1({
358
- ctx,
359
- id,
360
- magicString,
361
- path: p,
362
- raw: p.node.value,
363
- offset: 1,
364
- escape: true,
365
- markedArray
366
- });
367
- }
368
- },
369
- TemplateElement: {
370
- exit(p) {
371
- handleValue$1({
372
- ctx,
373
- id,
374
- magicString,
375
- path: p,
376
- raw: p.node.value.raw,
377
- offset: 0,
378
- escape: false,
379
- markedArray
380
- });
288
+ needUpdate && ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue);
381
289
  }
382
290
  }
383
291
  });
384
- return magicString.toString();
292
+ parser.write(ms.original);
293
+ parser.end();
294
+ return {
295
+ code: ms.toString()
296
+ };
385
297
  }
386
- function preProcessRawCode(options) {
387
- const { code, ctx } = options;
388
- const { replaceMap } = ctx;
389
- const magicString = typeof code === "string" ? new MagicString__default(code) : code;
390
- const markArr = [];
391
- for (const regex of ctx.preserveFunctionRegexs) {
392
- const allArr = [];
393
- let arr = null;
394
- while ((arr = regex.exec(magicString.original)) !== null) {
395
- allArr.push(arr);
396
- markArr.push([arr.index, arr.index + arr[0].length]);
397
- }
398
- for (const regExpMatch of allArr) {
399
- let ast;
400
- try {
401
- ast = parser$1.parse(regExpMatch[0], {
402
- sourceType: "unambiguous"
403
- });
404
- ast && traverse(ast, {
405
- StringLiteral: {
406
- enter(p) {
407
- const arr2 = fastSort.sort(shared.splitCode(p.node.value)).desc((x) => x.length);
408
- for (const v of arr2) {
409
- if (replaceMap.has(v)) {
410
- ctx.addPreserveClass(v);
411
- }
412
- }
413
- }
414
- },
415
- TemplateElement: {
416
- enter(p) {
417
- const arr2 = fastSort.sort(shared.splitCode(p.node.value.raw)).desc((x) => x.length);
418
- for (const v of arr2) {
419
- if (replaceMap.has(v)) {
420
- ctx.addPreserveClass(v);
421
- }
422
- }
423
- }
424
- }
425
- });
426
- } catch {
427
- continue;
428
- }
429
- }
430
- }
431
- for (const [key, value] of replaceMap) {
432
- const regex = new RegExp(escapeStringRegexp(key), "g");
433
- let arr = null;
434
- while ((arr = regex.exec(magicString.original)) !== null) {
435
- const start = arr.index;
436
- const end = arr.index + arr[0].length;
437
- let shouldUpdate = true;
438
- for (const [ps, pe] of markArr) {
439
- if (between(start, ps, pe) || between(end, ps, pe)) {
440
- shouldUpdate = false;
441
- break;
442
- }
443
- }
444
- if (shouldUpdate && typeof value === "string") {
445
- magicString.update(start, end, value);
446
- markArr.push([start, end]);
447
- }
448
- }
449
- }
450
- return magicString.toString();
298
+
299
+ function _interopDefaultCompat$1(e) {
300
+ return e && typeof e === "object" && "default" in e ? e.default : e;
451
301
  }
302
+ const traverse = _interopDefaultCompat$1(_babelTraverse__default);
452
303
 
453
304
  function handleValue(raw, node, options, ms, offset, escape$1) {
454
- const { ctx, splitQuote = true } = options;
305
+ const { ctx, splitQuote = true, id } = options;
455
306
  const { replaceMap, classGenerator: clsGen } = ctx;
456
307
  const array = shared.splitCode(raw, {
457
308
  splitQuote
@@ -465,7 +316,9 @@ function handleValue(raw, node, options, ms, offset, escape$1) {
465
316
  ignoreFlag = node.leadingComments.findIndex((x) => x.value.includes("tw-mangle") && x.value.includes("ignore")) > -1;
466
317
  }
467
318
  if (!ignoreFlag) {
468
- rawString = rawString.replace(shared.makeRegex(v), clsGen.generateClassName(v).name);
319
+ const gen = clsGen.generateClassName(v);
320
+ rawString = rawString.replace(shared.makeRegex(v), gen.name);
321
+ ctx.addToUsedBy(v, id);
469
322
  needUpdate = true;
470
323
  }
471
324
  }
@@ -481,10 +334,17 @@ function handleValue(raw, node, options, ms, offset, escape$1) {
481
334
  }
482
335
  function jsHandler(rawSource, options) {
483
336
  const ms = typeof rawSource === "string" ? new MagicString__default(rawSource) : rawSource;
484
- const ast = parser$1.parse(ms.original, {
485
- sourceType: "unambiguous",
486
- plugins: ["typescript", "jsx"]
487
- });
337
+ let ast;
338
+ try {
339
+ ast = parser$1.parse(ms.original, {
340
+ sourceType: "unambiguous"
341
+ });
342
+ } catch (error) {
343
+ return {
344
+ code: ms.original
345
+ };
346
+ }
347
+ const { ctx } = options;
488
348
  traverse(ast, {
489
349
  StringLiteral: {
490
350
  enter(p) {
@@ -497,25 +357,40 @@ function jsHandler(rawSource, options) {
497
357
  const n = p.node;
498
358
  handleValue(n.value.raw, n, options, ms, 0, false);
499
359
  }
360
+ },
361
+ CallExpression: {
362
+ enter(p) {
363
+ const callee = p.get("callee");
364
+ if (callee.isIdentifier() && ctx.isPreserveFunction(callee.node.name)) {
365
+ p.traverse({
366
+ StringLiteral: {
367
+ enter(path) {
368
+ const node = path.node;
369
+ const value = node.value;
370
+ const arr = fastSort.sort(shared.splitCode(value)).desc((x) => x.length);
371
+ for (const str of arr) {
372
+ if (ctx.replaceMap.has(str)) {
373
+ ctx.addPreserveClass(str);
374
+ }
375
+ }
376
+ }
377
+ },
378
+ TemplateElement: {
379
+ enter(path) {
380
+ const node = path.node;
381
+ const value = node.value.raw;
382
+ const arr = fastSort.sort(shared.splitCode(value)).desc((x) => x.length);
383
+ for (const str of arr) {
384
+ if (ctx.replaceMap.has(str)) {
385
+ ctx.addPreserveClass(str);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ });
391
+ }
392
+ }
500
393
  }
501
- // CallExpression: {
502
- // enter(p: NodePath<CallExpression>) {
503
- // const calleePath = p.get('callee')
504
- // if (calleePath.isIdentifier() && calleePath.node.name === 'eval') {
505
- // p.traverse({
506
- // StringLiteral: {
507
- // enter(s) {
508
- // // ___CSS_LOADER_EXPORT___
509
- // const res = jsHandler(s.node.value, options)
510
- // if (res.code) {
511
- // s.node.value = res.code
512
- // }
513
- // },
514
- // },
515
- // })
516
- // }
517
- // },
518
- // },
519
394
  });
520
395
  return {
521
396
  code: ms.toString(),
@@ -525,65 +400,9 @@ function jsHandler(rawSource, options) {
525
400
  };
526
401
  }
527
402
 
528
- function htmlHandler(raw, options) {
529
- const { ctx, isVue } = options;
530
- const { replaceMap } = ctx;
531
- const ms = typeof raw === "string" ? new MagicString__default(raw) : raw;
532
- const parser = new htmlparser2.Parser({
533
- onattribute(name, value) {
534
- if (name === "class") {
535
- const arr = shared.splitCode(value, {
536
- splitQuote: false
537
- });
538
- let rawValue = value;
539
- for (const v of arr) {
540
- if (replaceMap.has(v)) {
541
- rawValue = rawValue.replace(shared.makeRegex(v), ctx.classGenerator.generateClassName(v).name);
542
- }
543
- }
544
- ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue);
545
- }
546
- if (isVue) {
547
- if (name === ":class") {
548
- const { code } = jsHandler(value, {
549
- ctx
550
- });
551
- ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, code);
552
- }
553
- }
554
- }
555
- });
556
- parser.write(ms.original);
557
- parser.end();
558
- return ms.toString();
559
- }
560
-
561
- function vueHandler(raw, options) {
562
- const { ctx } = options;
563
- const ms = typeof raw === "string" ? new MagicString__default(raw) : raw;
564
- const { descriptor } = compilerSfc.parse(ms.original);
565
- const { template, scriptSetup, script } = descriptor;
566
- if (template) {
567
- const code = htmlHandler(template.content, { ctx, isVue: true });
568
- ms.update(template.loc.start.offset, template.loc.end.offset, code);
569
- }
570
- if (script) {
571
- const x = jsHandler(script.content, { ctx });
572
- ms.update(script.loc.start.offset, script.loc.end.offset, x.code);
573
- }
574
- if (scriptSetup) {
575
- const x = jsHandler(scriptSetup.content, { ctx });
576
- ms.update(scriptSetup.loc.start.offset, scriptSetup.loc.end.offset, x.code);
577
- }
578
- return ms.toString();
579
- }
580
-
581
403
  exports.ClassGenerator = shared.ClassGenerator;
582
404
  exports.Context = Context;
583
405
  exports.cssHandler = cssHandler;
584
406
  exports.handleValue = handleValue;
585
407
  exports.htmlHandler = htmlHandler;
586
408
  exports.jsHandler = jsHandler;
587
- exports.preProcessJs = preProcessJs;
588
- exports.preProcessRawCode = preProcessRawCode;
589
- exports.vueHandler = vueHandler;
package/dist/index.d.cts CHANGED
@@ -2,9 +2,8 @@ import * as _tailwindcss_mangle_config from '@tailwindcss-mangle/config';
2
2
  import { MangleUserConfig } from '@tailwindcss-mangle/config';
3
3
  import { ClassGenerator } from '@tailwindcss-mangle/shared';
4
4
  export { ClassGenerator } from '@tailwindcss-mangle/shared';
5
- import postcss from 'postcss';
6
- import * as MagicString from 'magic-string';
7
- import MagicString__default from 'magic-string';
5
+ import { TransformResult } from 'unplugin';
6
+ import MagicString from 'magic-string';
8
7
  import { StringLiteral, TemplateElement } from '@babel/types';
9
8
 
10
9
  interface InitConfigOptions {
@@ -14,8 +13,6 @@ interface InitConfigOptions {
14
13
  }
15
14
  declare class Context {
16
15
  options: MangleUserConfig;
17
- private includeMatcher;
18
- private excludeMatcher;
19
16
  replaceMap: Map<string, string>;
20
17
  classSet: Set<string>;
21
18
  classGenerator: ClassGenerator;
@@ -27,13 +24,13 @@ declare class Context {
27
24
  addPreserveClass(className: string): Set<string>;
28
25
  isPreserveFunction(calleeName: string): boolean;
29
26
  private mergeOptions;
30
- isInclude(file: string): boolean;
31
27
  currentMangleClassFilter(className: string): boolean;
32
28
  getClassSet(): Set<string>;
33
29
  getReplaceMap(): Map<string, string>;
34
- addToUsedBy(key: string, file: string): void;
30
+ addToUsedBy(key: string, file?: string): void;
35
31
  loadClassSet(classList: string[]): void;
36
32
  initConfig(opts?: InitConfigOptions): Promise<_tailwindcss_mangle_config.UserConfig>;
33
+ dump(): Promise<void>;
37
34
  }
38
35
 
39
36
  interface IClassGeneratorContextItem {
@@ -49,40 +46,28 @@ interface IClassGeneratorOptions {
49
46
  ignoreClass?: (string | RegExp)[];
50
47
  classPrefix?: string;
51
48
  }
49
+ interface IHandler {
50
+ (code: string, options: IHandlerOptions): IHandlerTransformResult;
51
+ }
52
+ type IHandlerTransformResult = Exclude<TransformResult, null | undefined | string>;
52
53
  interface IHandlerOptions {
53
54
  ctx: Context;
55
+ id?: string;
54
56
  }
55
57
  interface IHtmlHandlerOptions extends IHandlerOptions {
56
- isVue?: boolean;
57
58
  }
58
59
  interface IJsHandlerOptions extends IHandlerOptions {
59
60
  splitQuote?: boolean;
60
- minified?: boolean;
61
- }
62
- interface IVueHandlerOptions extends IHandlerOptions {
63
61
  }
64
62
  interface ICssHandlerOptions extends IHandlerOptions {
65
63
  ignoreVueScoped?: boolean;
66
- file?: string;
67
- }
68
- interface IPreProcessJsOptions extends IHandlerOptions {
69
- code: string | MagicString__default;
70
- id: string;
71
64
  }
72
65
 
73
- declare function cssHandler(rawSource: string, options: ICssHandlerOptions): postcss.LazyResult<postcss.Root>;
74
-
75
- declare function htmlHandler(raw: string | MagicString__default, options: IHtmlHandlerOptions): string;
76
-
77
- declare function preProcessJs(options: IPreProcessJsOptions): string;
78
- declare function preProcessRawCode(options: IPreProcessJsOptions): string;
66
+ declare function cssHandler(rawSource: string, options: ICssHandlerOptions): Promise<IHandlerTransformResult>;
79
67
 
80
- declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString__default, offset: number, escape: boolean): string;
81
- declare function jsHandler(rawSource: string | MagicString__default, options: IJsHandlerOptions): {
82
- code: string;
83
- readonly map: MagicString.SourceMap;
84
- };
68
+ declare function htmlHandler(raw: string | MagicString, options: IHtmlHandlerOptions): IHandlerTransformResult;
85
69
 
86
- declare function vueHandler(raw: string | MagicString__default, options: IVueHandlerOptions): string;
70
+ declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString, offset: number, escape: boolean): string;
71
+ declare function jsHandler(rawSource: string | MagicString, options: IJsHandlerOptions): IHandlerTransformResult;
87
72
 
88
- export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandlerOptions, type IHtmlHandlerOptions, type IJsHandlerOptions, type IPreProcessJsOptions, type IVueHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode, vueHandler };
73
+ export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandler, type IHandlerOptions, type IHandlerTransformResult, type IHtmlHandlerOptions, type IJsHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler };
package/dist/index.d.mts CHANGED
@@ -2,9 +2,8 @@ import * as _tailwindcss_mangle_config from '@tailwindcss-mangle/config';
2
2
  import { MangleUserConfig } from '@tailwindcss-mangle/config';
3
3
  import { ClassGenerator } from '@tailwindcss-mangle/shared';
4
4
  export { ClassGenerator } from '@tailwindcss-mangle/shared';
5
- import postcss from 'postcss';
6
- import * as MagicString from 'magic-string';
7
- import MagicString__default from 'magic-string';
5
+ import { TransformResult } from 'unplugin';
6
+ import MagicString from 'magic-string';
8
7
  import { StringLiteral, TemplateElement } from '@babel/types';
9
8
 
10
9
  interface InitConfigOptions {
@@ -14,8 +13,6 @@ interface InitConfigOptions {
14
13
  }
15
14
  declare class Context {
16
15
  options: MangleUserConfig;
17
- private includeMatcher;
18
- private excludeMatcher;
19
16
  replaceMap: Map<string, string>;
20
17
  classSet: Set<string>;
21
18
  classGenerator: ClassGenerator;
@@ -27,13 +24,13 @@ declare class Context {
27
24
  addPreserveClass(className: string): Set<string>;
28
25
  isPreserveFunction(calleeName: string): boolean;
29
26
  private mergeOptions;
30
- isInclude(file: string): boolean;
31
27
  currentMangleClassFilter(className: string): boolean;
32
28
  getClassSet(): Set<string>;
33
29
  getReplaceMap(): Map<string, string>;
34
- addToUsedBy(key: string, file: string): void;
30
+ addToUsedBy(key: string, file?: string): void;
35
31
  loadClassSet(classList: string[]): void;
36
32
  initConfig(opts?: InitConfigOptions): Promise<_tailwindcss_mangle_config.UserConfig>;
33
+ dump(): Promise<void>;
37
34
  }
38
35
 
39
36
  interface IClassGeneratorContextItem {
@@ -49,40 +46,28 @@ interface IClassGeneratorOptions {
49
46
  ignoreClass?: (string | RegExp)[];
50
47
  classPrefix?: string;
51
48
  }
49
+ interface IHandler {
50
+ (code: string, options: IHandlerOptions): IHandlerTransformResult;
51
+ }
52
+ type IHandlerTransformResult = Exclude<TransformResult, null | undefined | string>;
52
53
  interface IHandlerOptions {
53
54
  ctx: Context;
55
+ id?: string;
54
56
  }
55
57
  interface IHtmlHandlerOptions extends IHandlerOptions {
56
- isVue?: boolean;
57
58
  }
58
59
  interface IJsHandlerOptions extends IHandlerOptions {
59
60
  splitQuote?: boolean;
60
- minified?: boolean;
61
- }
62
- interface IVueHandlerOptions extends IHandlerOptions {
63
61
  }
64
62
  interface ICssHandlerOptions extends IHandlerOptions {
65
63
  ignoreVueScoped?: boolean;
66
- file?: string;
67
- }
68
- interface IPreProcessJsOptions extends IHandlerOptions {
69
- code: string | MagicString__default;
70
- id: string;
71
64
  }
72
65
 
73
- declare function cssHandler(rawSource: string, options: ICssHandlerOptions): postcss.LazyResult<postcss.Root>;
74
-
75
- declare function htmlHandler(raw: string | MagicString__default, options: IHtmlHandlerOptions): string;
76
-
77
- declare function preProcessJs(options: IPreProcessJsOptions): string;
78
- declare function preProcessRawCode(options: IPreProcessJsOptions): string;
66
+ declare function cssHandler(rawSource: string, options: ICssHandlerOptions): Promise<IHandlerTransformResult>;
79
67
 
80
- declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString__default, offset: number, escape: boolean): string;
81
- declare function jsHandler(rawSource: string | MagicString__default, options: IJsHandlerOptions): {
82
- code: string;
83
- readonly map: MagicString.SourceMap;
84
- };
68
+ declare function htmlHandler(raw: string | MagicString, options: IHtmlHandlerOptions): IHandlerTransformResult;
85
69
 
86
- declare function vueHandler(raw: string | MagicString__default, options: IVueHandlerOptions): string;
70
+ declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString, offset: number, escape: boolean): string;
71
+ declare function jsHandler(rawSource: string | MagicString, options: IJsHandlerOptions): IHandlerTransformResult;
87
72
 
88
- export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandlerOptions, type IHtmlHandlerOptions, type IJsHandlerOptions, type IPreProcessJsOptions, type IVueHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode, vueHandler };
73
+ export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandler, type IHandlerOptions, type IHandlerTransformResult, type IHtmlHandlerOptions, type IJsHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler };
package/dist/index.d.ts CHANGED
@@ -2,9 +2,8 @@ import * as _tailwindcss_mangle_config from '@tailwindcss-mangle/config';
2
2
  import { MangleUserConfig } from '@tailwindcss-mangle/config';
3
3
  import { ClassGenerator } from '@tailwindcss-mangle/shared';
4
4
  export { ClassGenerator } from '@tailwindcss-mangle/shared';
5
- import postcss from 'postcss';
6
- import * as MagicString from 'magic-string';
7
- import MagicString__default from 'magic-string';
5
+ import { TransformResult } from 'unplugin';
6
+ import MagicString from 'magic-string';
8
7
  import { StringLiteral, TemplateElement } from '@babel/types';
9
8
 
10
9
  interface InitConfigOptions {
@@ -14,8 +13,6 @@ interface InitConfigOptions {
14
13
  }
15
14
  declare class Context {
16
15
  options: MangleUserConfig;
17
- private includeMatcher;
18
- private excludeMatcher;
19
16
  replaceMap: Map<string, string>;
20
17
  classSet: Set<string>;
21
18
  classGenerator: ClassGenerator;
@@ -27,13 +24,13 @@ declare class Context {
27
24
  addPreserveClass(className: string): Set<string>;
28
25
  isPreserveFunction(calleeName: string): boolean;
29
26
  private mergeOptions;
30
- isInclude(file: string): boolean;
31
27
  currentMangleClassFilter(className: string): boolean;
32
28
  getClassSet(): Set<string>;
33
29
  getReplaceMap(): Map<string, string>;
34
- addToUsedBy(key: string, file: string): void;
30
+ addToUsedBy(key: string, file?: string): void;
35
31
  loadClassSet(classList: string[]): void;
36
32
  initConfig(opts?: InitConfigOptions): Promise<_tailwindcss_mangle_config.UserConfig>;
33
+ dump(): Promise<void>;
37
34
  }
38
35
 
39
36
  interface IClassGeneratorContextItem {
@@ -49,40 +46,28 @@ interface IClassGeneratorOptions {
49
46
  ignoreClass?: (string | RegExp)[];
50
47
  classPrefix?: string;
51
48
  }
49
+ interface IHandler {
50
+ (code: string, options: IHandlerOptions): IHandlerTransformResult;
51
+ }
52
+ type IHandlerTransformResult = Exclude<TransformResult, null | undefined | string>;
52
53
  interface IHandlerOptions {
53
54
  ctx: Context;
55
+ id?: string;
54
56
  }
55
57
  interface IHtmlHandlerOptions extends IHandlerOptions {
56
- isVue?: boolean;
57
58
  }
58
59
  interface IJsHandlerOptions extends IHandlerOptions {
59
60
  splitQuote?: boolean;
60
- minified?: boolean;
61
- }
62
- interface IVueHandlerOptions extends IHandlerOptions {
63
61
  }
64
62
  interface ICssHandlerOptions extends IHandlerOptions {
65
63
  ignoreVueScoped?: boolean;
66
- file?: string;
67
- }
68
- interface IPreProcessJsOptions extends IHandlerOptions {
69
- code: string | MagicString__default;
70
- id: string;
71
64
  }
72
65
 
73
- declare function cssHandler(rawSource: string, options: ICssHandlerOptions): postcss.LazyResult<postcss.Root>;
74
-
75
- declare function htmlHandler(raw: string | MagicString__default, options: IHtmlHandlerOptions): string;
76
-
77
- declare function preProcessJs(options: IPreProcessJsOptions): string;
78
- declare function preProcessRawCode(options: IPreProcessJsOptions): string;
66
+ declare function cssHandler(rawSource: string, options: ICssHandlerOptions): Promise<IHandlerTransformResult>;
79
67
 
80
- declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString__default, offset: number, escape: boolean): string;
81
- declare function jsHandler(rawSource: string | MagicString__default, options: IJsHandlerOptions): {
82
- code: string;
83
- readonly map: MagicString.SourceMap;
84
- };
68
+ declare function htmlHandler(raw: string | MagicString, options: IHtmlHandlerOptions): IHandlerTransformResult;
85
69
 
86
- declare function vueHandler(raw: string | MagicString__default, options: IVueHandlerOptions): string;
70
+ declare function handleValue(raw: string, node: StringLiteral | TemplateElement, options: IJsHandlerOptions, ms: MagicString, offset: number, escape: boolean): string;
71
+ declare function jsHandler(rawSource: string | MagicString, options: IJsHandlerOptions): IHandlerTransformResult;
87
72
 
88
- export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandlerOptions, type IHtmlHandlerOptions, type IJsHandlerOptions, type IPreProcessJsOptions, type IVueHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode, vueHandler };
73
+ export { Context, type IClassGeneratorContextItem, type IClassGeneratorOptions, type ICssHandlerOptions, type IHandler, type IHandlerOptions, type IHandlerTransformResult, type IHtmlHandlerOptions, type IJsHandlerOptions, cssHandler, handleValue, htmlHandler, jsHandler };
package/dist/index.mjs CHANGED
@@ -1,11 +1,10 @@
1
1
  import fs from 'node:fs';
2
- import { resolve, isAbsolute } from 'node:path';
2
+ import { resolve, isAbsolute, dirname } from 'node:path';
3
3
  import process from 'node:process';
4
4
  import { ClassGenerator, defaultMangleClassFilter, splitCode, makeRegex } from '@tailwindcss-mangle/shared';
5
5
  export { ClassGenerator } from '@tailwindcss-mangle/shared';
6
6
  import { getConfig } from '@tailwindcss-mangle/config';
7
7
  import { sort } from 'fast-sort';
8
- import micromatch from 'micromatch';
9
8
  import postcss from 'postcss';
10
9
  import parser from 'postcss-selector-parser';
11
10
  import { Parser } from 'htmlparser2';
@@ -13,7 +12,6 @@ import MagicString from 'magic-string';
13
12
  import { jsStringEscape } from '@ast-core/escape';
14
13
  import _babelTraverse from '@babel/traverse';
15
14
  import { parse } from '@babel/parser';
16
- import { parse as parse$1 } from '@vue/compiler-sfc';
17
15
 
18
16
  function isPlainObject(value) {
19
17
  if (value === null || typeof value !== "object") {
@@ -71,23 +69,12 @@ function createDefu(merger) {
71
69
  }
72
70
  const defu = createDefu();
73
71
 
74
- const { isMatch } = micromatch;
75
72
  function escapeStringRegexp(str) {
76
73
  if (typeof str !== "string") {
77
74
  throw new TypeError("Expected a string");
78
75
  }
79
76
  return str.replaceAll(/[$()*+.?[\\\]^{|}]/g, "\\$&").replaceAll("-", "\\x2d");
80
77
  }
81
- function createGlobMatcher(pattern, fallbackValue = false) {
82
- if (pattern === void 0) {
83
- return function() {
84
- return fallbackValue;
85
- };
86
- }
87
- return function(file) {
88
- return isMatch(file, pattern);
89
- };
90
- }
91
78
 
92
79
  var __defProp = Object.defineProperty;
93
80
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -98,8 +85,6 @@ var __publicField = (obj, key, value) => {
98
85
  class Context {
99
86
  constructor() {
100
87
  __publicField(this, "options");
101
- __publicField(this, "includeMatcher");
102
- __publicField(this, "excludeMatcher");
103
88
  __publicField(this, "replaceMap");
104
89
  __publicField(this, "classSet");
105
90
  __publicField(this, "classGenerator");
@@ -109,8 +94,6 @@ class Context {
109
94
  this.options = {};
110
95
  this.classSet = /* @__PURE__ */ new Set();
111
96
  this.replaceMap = /* @__PURE__ */ new Map();
112
- this.includeMatcher = () => true;
113
- this.excludeMatcher = () => false;
114
97
  this.classGenerator = new ClassGenerator();
115
98
  this.preserveFunctionSet = /* @__PURE__ */ new Set();
116
99
  this.preserveClassNamesSet = /* @__PURE__ */ new Set();
@@ -127,17 +110,12 @@ class Context {
127
110
  }
128
111
  mergeOptions(...opts) {
129
112
  this.options = defu(this.options, ...opts);
130
- this.includeMatcher = createGlobMatcher(this.options.include, true);
131
- this.excludeMatcher = createGlobMatcher(this.options.exclude, false);
132
113
  this.classGenerator = new ClassGenerator(this.options.classGenerator);
133
114
  this.preserveFunctionSet = new Set(this.options?.preserveFunction ?? []);
134
115
  this.preserveFunctionRegexs = [...this.preserveFunctionSet.values()].map((x) => {
135
116
  return new RegExp(`${escapeStringRegexp(x)}\\(([^)]*)\\)`, "g");
136
117
  });
137
118
  }
138
- isInclude(file) {
139
- return this.includeMatcher(file) && !this.excludeMatcher(file);
140
- }
141
119
  currentMangleClassFilter(className) {
142
120
  return (this.options.mangleClassFilter ?? defaultMangleClassFilter)(className);
143
121
  }
@@ -148,6 +126,9 @@ class Context {
148
126
  return this.replaceMap;
149
127
  }
150
128
  addToUsedBy(key, file) {
129
+ if (!file) {
130
+ return;
131
+ }
151
132
  const hit = this.classGenerator.newClassMap[key];
152
133
  if (hit) {
153
134
  hit.usedBy.add(file);
@@ -164,6 +145,12 @@ class Context {
164
145
  async initConfig(opts = {}) {
165
146
  const { cwd, classList: _classList, mangleOptions } = opts;
166
147
  const { config, cwd: configCwd } = await getConfig(cwd);
148
+ if (mangleOptions?.classMapOutput === true) {
149
+ mangleOptions.classMapOutput = config.mangle?.classMapOutput;
150
+ if (typeof mangleOptions.classMapOutput === "object") {
151
+ mangleOptions.classMapOutput.enable = true;
152
+ }
153
+ }
167
154
  this.mergeOptions(mangleOptions, config?.mangle);
168
155
  if (_classList) {
169
156
  this.loadClassSet(_classList);
@@ -186,7 +173,25 @@ class Context {
186
173
  }
187
174
  return config;
188
175
  }
189
- // ["clsx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
176
+ async dump() {
177
+ try {
178
+ const arr = Object.entries(this.classGenerator.newClassMap).map((x) => {
179
+ return {
180
+ before: x[0],
181
+ after: x[1].name,
182
+ usedBy: Array.from(x[1].usedBy)
183
+ };
184
+ });
185
+ if (typeof this.options.classMapOutput === "function") {
186
+ await this.options.classMapOutput(arr);
187
+ } else if (typeof this.options.classMapOutput === "object" && this.options.classMapOutput.enable && this.options.classMapOutput.filename) {
188
+ fs.mkdirSync(dirname(this.options.classMapOutput.filename), { recursive: true });
189
+ fs.writeFileSync(this.options.classMapOutput.filename, JSON.stringify(arr, null, 2));
190
+ }
191
+ } catch (error) {
192
+ console.error(`[tailwindcss-mangle]: ${error}`);
193
+ }
194
+ }
190
195
  }
191
196
 
192
197
  const postcssPlugin = "postcss-mangle-tailwindcss-plugin";
@@ -203,7 +208,7 @@ function isVueScoped(s) {
203
208
  return false;
204
209
  }
205
210
  const transformSelectorPostcssPlugin = function(options) {
206
- const { ignoreVueScoped, ctx } = defu(options, {
211
+ const { ignoreVueScoped, ctx, id } = defu(options, {
207
212
  ignoreVueScoped: true
208
213
  });
209
214
  const replaceMap = ctx.replaceMap;
@@ -236,211 +241,58 @@ const transformSelectorPostcssPlugin = function(options) {
236
241
  };
237
242
  transformSelectorPostcssPlugin.postcss = true;
238
243
 
239
- function cssHandler(rawSource, options) {
244
+ async function cssHandler(rawSource, options) {
240
245
  const acceptedPlugins = [transformSelectorPostcssPlugin(options)];
241
- const { file } = options;
242
- return postcss(acceptedPlugins).process(rawSource, {
243
- from: file,
244
- to: file
246
+ const { id } = options;
247
+ const { css: code, map } = await postcss(acceptedPlugins).process(rawSource, {
248
+ from: id,
249
+ to: id
245
250
  });
251
+ return {
252
+ code,
253
+ // @ts-ignore
254
+ map
255
+ };
246
256
  }
247
257
 
248
- function _interopDefaultCompat(e) {
249
- return e && typeof e === "object" && "default" in e ? e.default : e;
250
- }
251
- const traverse = _interopDefaultCompat(_babelTraverse);
252
-
253
- function between(x, min, max, included = false) {
254
- if (typeof x !== "number") {
255
- return false;
256
- }
257
- return included ? x >= min && x <= max : x > min && x < max;
258
- }
259
-
260
- function handleValue$1(options) {
261
- const { ctx, id, path, magicString, raw, offset = 0, escape = false, markedArray } = options;
262
- const { replaceMap } = ctx;
263
- const node = path.node;
264
- let value = raw;
265
- for (const [s, e] of markedArray) {
266
- if (between(node.start, s, e) || between(node.end, s, e)) {
267
- return;
268
- }
269
- }
270
- const arr = sort(splitCode(value)).desc((x) => x.length);
271
- for (const str of arr) {
272
- if (replaceMap.has(str)) {
273
- ctx.addToUsedBy(str, id);
274
- const v = replaceMap.get(str);
275
- if (v && typeof v === "string") {
276
- value = value.replaceAll(str, v);
277
- }
278
- }
279
- }
280
- if (typeof node.start === "number" && typeof node.end === "number" && value) {
281
- const start = node.start + offset;
282
- const end = node.end - offset;
283
- if (start < end) {
284
- magicString.update(start, end, escape ? jsStringEscape(value) : value);
285
- }
286
- }
287
- }
288
- function preProcessJs(options) {
289
- const { code, id, ctx } = options;
290
- const { replaceMap } = ctx;
291
- const magicString = typeof code === "string" ? new MagicString(code) : code;
292
- let ast;
293
- try {
294
- const file = parse(magicString.original, {
295
- sourceType: "unambiguous",
296
- plugins: ["typescript", "jsx"]
297
- });
298
- if (file) {
299
- ast = file;
300
- } else {
301
- return code.toString();
302
- }
303
- } catch {
304
- return code.toString();
305
- }
306
- const markedArray = [];
307
- traverse(ast, {
308
- CallExpression: {
309
- enter(p) {
310
- const callee = p.get("callee");
311
- if (callee.isIdentifier() && ctx.isPreserveFunction(callee.node.name)) {
312
- if (p.node.start && p.node.end) {
313
- markedArray.push([p.node.start, p.node.end]);
258
+ function htmlHandler(raw, options) {
259
+ const { ctx, id } = options;
260
+ const { replaceMap, classGenerator } = ctx;
261
+ const ms = typeof raw === "string" ? new MagicString(raw) : raw;
262
+ const parser = new Parser({
263
+ onattribute(name, value) {
264
+ if (name === "class") {
265
+ let needUpdate = false;
266
+ const arr = splitCode(value, {
267
+ splitQuote: false
268
+ });
269
+ let rawValue = value;
270
+ for (const v of arr) {
271
+ if (replaceMap.has(v)) {
272
+ const gen = classGenerator.generateClassName(v);
273
+ rawValue = rawValue.replace(makeRegex(v), gen.name);
274
+ ctx.addToUsedBy(v, id);
275
+ needUpdate = true;
314
276
  }
315
- p.traverse({
316
- StringLiteral: {
317
- enter(path) {
318
- const node = path.node;
319
- const value = node.value;
320
- const arr = sort(splitCode(value)).desc((x) => x.length);
321
- for (const str of arr) {
322
- if (replaceMap.has(str)) {
323
- ctx.addPreserveClass(str);
324
- }
325
- }
326
- }
327
- },
328
- TemplateElement: {
329
- enter(path) {
330
- const node = path.node;
331
- const value = node.value.raw;
332
- const arr = sort(splitCode(value)).desc((x) => x.length);
333
- for (const str of arr) {
334
- if (replaceMap.has(str)) {
335
- ctx.addPreserveClass(str);
336
- }
337
- }
338
- }
339
- }
340
- });
341
277
  }
342
- }
343
- },
344
- StringLiteral: {
345
- exit(p) {
346
- handleValue$1({
347
- ctx,
348
- id,
349
- magicString,
350
- path: p,
351
- raw: p.node.value,
352
- offset: 1,
353
- escape: true,
354
- markedArray
355
- });
356
- }
357
- },
358
- TemplateElement: {
359
- exit(p) {
360
- handleValue$1({
361
- ctx,
362
- id,
363
- magicString,
364
- path: p,
365
- raw: p.node.value.raw,
366
- offset: 0,
367
- escape: false,
368
- markedArray
369
- });
278
+ needUpdate && ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue);
370
279
  }
371
280
  }
372
281
  });
373
- return magicString.toString();
282
+ parser.write(ms.original);
283
+ parser.end();
284
+ return {
285
+ code: ms.toString()
286
+ };
374
287
  }
375
- function preProcessRawCode(options) {
376
- const { code, ctx } = options;
377
- const { replaceMap } = ctx;
378
- const magicString = typeof code === "string" ? new MagicString(code) : code;
379
- const markArr = [];
380
- for (const regex of ctx.preserveFunctionRegexs) {
381
- const allArr = [];
382
- let arr = null;
383
- while ((arr = regex.exec(magicString.original)) !== null) {
384
- allArr.push(arr);
385
- markArr.push([arr.index, arr.index + arr[0].length]);
386
- }
387
- for (const regExpMatch of allArr) {
388
- let ast;
389
- try {
390
- ast = parse(regExpMatch[0], {
391
- sourceType: "unambiguous"
392
- });
393
- ast && traverse(ast, {
394
- StringLiteral: {
395
- enter(p) {
396
- const arr2 = sort(splitCode(p.node.value)).desc((x) => x.length);
397
- for (const v of arr2) {
398
- if (replaceMap.has(v)) {
399
- ctx.addPreserveClass(v);
400
- }
401
- }
402
- }
403
- },
404
- TemplateElement: {
405
- enter(p) {
406
- const arr2 = sort(splitCode(p.node.value.raw)).desc((x) => x.length);
407
- for (const v of arr2) {
408
- if (replaceMap.has(v)) {
409
- ctx.addPreserveClass(v);
410
- }
411
- }
412
- }
413
- }
414
- });
415
- } catch {
416
- continue;
417
- }
418
- }
419
- }
420
- for (const [key, value] of replaceMap) {
421
- const regex = new RegExp(escapeStringRegexp(key), "g");
422
- let arr = null;
423
- while ((arr = regex.exec(magicString.original)) !== null) {
424
- const start = arr.index;
425
- const end = arr.index + arr[0].length;
426
- let shouldUpdate = true;
427
- for (const [ps, pe] of markArr) {
428
- if (between(start, ps, pe) || between(end, ps, pe)) {
429
- shouldUpdate = false;
430
- break;
431
- }
432
- }
433
- if (shouldUpdate && typeof value === "string") {
434
- magicString.update(start, end, value);
435
- markArr.push([start, end]);
436
- }
437
- }
438
- }
439
- return magicString.toString();
288
+
289
+ function _interopDefaultCompat(e) {
290
+ return e && typeof e === "object" && "default" in e ? e.default : e;
440
291
  }
292
+ const traverse = _interopDefaultCompat(_babelTraverse);
441
293
 
442
294
  function handleValue(raw, node, options, ms, offset, escape) {
443
- const { ctx, splitQuote = true } = options;
295
+ const { ctx, splitQuote = true, id } = options;
444
296
  const { replaceMap, classGenerator: clsGen } = ctx;
445
297
  const array = splitCode(raw, {
446
298
  splitQuote
@@ -454,7 +306,9 @@ function handleValue(raw, node, options, ms, offset, escape) {
454
306
  ignoreFlag = node.leadingComments.findIndex((x) => x.value.includes("tw-mangle") && x.value.includes("ignore")) > -1;
455
307
  }
456
308
  if (!ignoreFlag) {
457
- rawString = rawString.replace(makeRegex(v), clsGen.generateClassName(v).name);
309
+ const gen = clsGen.generateClassName(v);
310
+ rawString = rawString.replace(makeRegex(v), gen.name);
311
+ ctx.addToUsedBy(v, id);
458
312
  needUpdate = true;
459
313
  }
460
314
  }
@@ -470,10 +324,17 @@ function handleValue(raw, node, options, ms, offset, escape) {
470
324
  }
471
325
  function jsHandler(rawSource, options) {
472
326
  const ms = typeof rawSource === "string" ? new MagicString(rawSource) : rawSource;
473
- const ast = parse(ms.original, {
474
- sourceType: "unambiguous",
475
- plugins: ["typescript", "jsx"]
476
- });
327
+ let ast;
328
+ try {
329
+ ast = parse(ms.original, {
330
+ sourceType: "unambiguous"
331
+ });
332
+ } catch (error) {
333
+ return {
334
+ code: ms.original
335
+ };
336
+ }
337
+ const { ctx } = options;
477
338
  traverse(ast, {
478
339
  StringLiteral: {
479
340
  enter(p) {
@@ -486,25 +347,40 @@ function jsHandler(rawSource, options) {
486
347
  const n = p.node;
487
348
  handleValue(n.value.raw, n, options, ms, 0, false);
488
349
  }
350
+ },
351
+ CallExpression: {
352
+ enter(p) {
353
+ const callee = p.get("callee");
354
+ if (callee.isIdentifier() && ctx.isPreserveFunction(callee.node.name)) {
355
+ p.traverse({
356
+ StringLiteral: {
357
+ enter(path) {
358
+ const node = path.node;
359
+ const value = node.value;
360
+ const arr = sort(splitCode(value)).desc((x) => x.length);
361
+ for (const str of arr) {
362
+ if (ctx.replaceMap.has(str)) {
363
+ ctx.addPreserveClass(str);
364
+ }
365
+ }
366
+ }
367
+ },
368
+ TemplateElement: {
369
+ enter(path) {
370
+ const node = path.node;
371
+ const value = node.value.raw;
372
+ const arr = sort(splitCode(value)).desc((x) => x.length);
373
+ for (const str of arr) {
374
+ if (ctx.replaceMap.has(str)) {
375
+ ctx.addPreserveClass(str);
376
+ }
377
+ }
378
+ }
379
+ }
380
+ });
381
+ }
382
+ }
489
383
  }
490
- // CallExpression: {
491
- // enter(p: NodePath<CallExpression>) {
492
- // const calleePath = p.get('callee')
493
- // if (calleePath.isIdentifier() && calleePath.node.name === 'eval') {
494
- // p.traverse({
495
- // StringLiteral: {
496
- // enter(s) {
497
- // // ___CSS_LOADER_EXPORT___
498
- // const res = jsHandler(s.node.value, options)
499
- // if (res.code) {
500
- // s.node.value = res.code
501
- // }
502
- // },
503
- // },
504
- // })
505
- // }
506
- // },
507
- // },
508
384
  });
509
385
  return {
510
386
  code: ms.toString(),
@@ -514,57 +390,4 @@ function jsHandler(rawSource, options) {
514
390
  };
515
391
  }
516
392
 
517
- function htmlHandler(raw, options) {
518
- const { ctx, isVue } = options;
519
- const { replaceMap } = ctx;
520
- const ms = typeof raw === "string" ? new MagicString(raw) : raw;
521
- const parser = new Parser({
522
- onattribute(name, value) {
523
- if (name === "class") {
524
- const arr = splitCode(value, {
525
- splitQuote: false
526
- });
527
- let rawValue = value;
528
- for (const v of arr) {
529
- if (replaceMap.has(v)) {
530
- rawValue = rawValue.replace(makeRegex(v), ctx.classGenerator.generateClassName(v).name);
531
- }
532
- }
533
- ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue);
534
- }
535
- if (isVue) {
536
- if (name === ":class") {
537
- const { code } = jsHandler(value, {
538
- ctx
539
- });
540
- ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, code);
541
- }
542
- }
543
- }
544
- });
545
- parser.write(ms.original);
546
- parser.end();
547
- return ms.toString();
548
- }
549
-
550
- function vueHandler(raw, options) {
551
- const { ctx } = options;
552
- const ms = typeof raw === "string" ? new MagicString(raw) : raw;
553
- const { descriptor } = parse$1(ms.original);
554
- const { template, scriptSetup, script } = descriptor;
555
- if (template) {
556
- const code = htmlHandler(template.content, { ctx, isVue: true });
557
- ms.update(template.loc.start.offset, template.loc.end.offset, code);
558
- }
559
- if (script) {
560
- const x = jsHandler(script.content, { ctx });
561
- ms.update(script.loc.start.offset, script.loc.end.offset, x.code);
562
- }
563
- if (scriptSetup) {
564
- const x = jsHandler(scriptSetup.content, { ctx });
565
- ms.update(scriptSetup.loc.start.offset, scriptSetup.loc.end.offset, x.code);
566
- }
567
- return ms.toString();
568
- }
569
-
570
- export { Context, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode, vueHandler };
393
+ export { Context, cssHandler, handleValue, htmlHandler, jsHandler };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailwindcss-mangle/core",
3
- "version": "2.3.0",
3
+ "version": "3.0.0",
4
4
  "description": "The core of tailwindcss-mangle",
5
5
  "author": "SonOfMagic <qq1324318532@gmail.com>",
6
6
  "license": "MIT",
@@ -48,24 +48,16 @@
48
48
  "@babel/parser": "^7.24.7",
49
49
  "@babel/traverse": "^7.24.7",
50
50
  "@babel/types": "^7.24.7",
51
- "@vue/compiler-sfc": "^3.4.29",
52
51
  "fast-sort": "^3.4.0",
53
52
  "htmlparser2": "9.1.0",
54
53
  "magic-string": "^0.30.10",
55
- "micromatch": "^4.0.7",
56
54
  "postcss": "^8.4.38",
57
55
  "postcss-selector-parser": "^6.1.0",
58
- "@tailwindcss-mangle/config": "^2.2.2",
59
- "@tailwindcss-mangle/shared": "^2.2.2"
56
+ "@tailwindcss-mangle/config": "^3.0.0",
57
+ "@tailwindcss-mangle/shared": "^3.0.0"
60
58
  },
61
59
  "devDependencies": {
62
- "@types/babel__traverse": "^7.20.6",
63
- "@types/micromatch": "^4.0.7",
64
- "@vue/compiler-core": "^3.4.29",
65
- "@vue/compiler-sfc": "^3.4.27"
66
- },
67
- "directories": {
68
- "test": "test"
60
+ "@types/babel__traverse": "^7.20.6"
69
61
  },
70
62
  "scripts": {
71
63
  "dev": "unbuild --sourcemap",