@tailwindcss-mangle/core 2.2.2 → 2.3.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.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import { resolve, isAbsolute } from 'node:path';
3
+ import process from 'node:process';
3
4
  import { ClassGenerator, defaultMangleClassFilter, splitCode, makeRegex } from '@tailwindcss-mangle/shared';
4
5
  export { ClassGenerator } from '@tailwindcss-mangle/shared';
5
6
  import { getConfig } from '@tailwindcss-mangle/config';
@@ -7,26 +8,32 @@ import { sort } from 'fast-sort';
7
8
  import micromatch from 'micromatch';
8
9
  import postcss from 'postcss';
9
10
  import parser from 'postcss-selector-parser';
10
- import { html, defaultTreeAdapter, parse, serialize } from 'parse5';
11
- import babel, { transformSync as transformSync$1 } from '@babel/core';
12
- import { declare } from '@babel/helper-plugin-utils';
11
+ import { Parser } from 'htmlparser2';
13
12
  import MagicString from 'magic-string';
14
13
  import { jsStringEscape } from '@ast-core/escape';
14
+ import _babelTraverse from '@babel/traverse';
15
+ import { parse } from '@babel/parser';
16
+ import { parse as parse$1 } from '@vue/compiler-sfc';
15
17
 
16
-
17
-
18
- // -- Unbuild CommonJS Shims --
19
- import __cjs_url__ from 'url';
20
- import __cjs_path__ from 'path';
21
- import __cjs_mod__ from 'module';
22
- const __filename = __cjs_url__.fileURLToPath(import.meta.url);
23
- const __dirname = __cjs_path__.dirname(__filename);
24
- const require = __cjs_mod__.createRequire(import.meta.url);
25
- function isObject(value) {
26
- return value !== null && typeof value === "object";
18
+ function isPlainObject(value) {
19
+ if (value === null || typeof value !== "object") {
20
+ return false;
21
+ }
22
+ const prototype = Object.getPrototypeOf(value);
23
+ if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) {
24
+ return false;
25
+ }
26
+ if (Symbol.iterator in value) {
27
+ return false;
28
+ }
29
+ if (Symbol.toStringTag in value) {
30
+ return Object.prototype.toString.call(value) === "[object Module]";
31
+ }
32
+ return true;
27
33
  }
34
+
28
35
  function _defu(baseObject, defaults, namespace = ".", merger) {
29
- if (!isObject(defaults)) {
36
+ if (!isPlainObject(defaults)) {
30
37
  return _defu(baseObject, {}, namespace, merger);
31
38
  }
32
39
  const object = Object.assign({}, defaults);
@@ -43,7 +50,7 @@ function _defu(baseObject, defaults, namespace = ".", merger) {
43
50
  }
44
51
  if (Array.isArray(value) && Array.isArray(object[key])) {
45
52
  object[key] = [...value, ...object[key]];
46
- } else if (isObject(value) && isObject(object[key])) {
53
+ } else if (isPlainObject(value) && isPlainObject(object[key])) {
47
54
  object[key] = _defu(
48
55
  value,
49
56
  object[key],
@@ -125,7 +132,7 @@ class Context {
125
132
  this.classGenerator = new ClassGenerator(this.options.classGenerator);
126
133
  this.preserveFunctionSet = new Set(this.options?.preserveFunction ?? []);
127
134
  this.preserveFunctionRegexs = [...this.preserveFunctionSet.values()].map((x) => {
128
- return new RegExp(escapeStringRegexp(x) + "\\(([^)]*)\\)", "g");
135
+ return new RegExp(`${escapeStringRegexp(x)}\\(([^)]*)\\)`, "g");
129
136
  });
130
137
  }
131
138
  isInclude(file) {
@@ -183,7 +190,6 @@ class Context {
183
190
  }
184
191
 
185
192
  const postcssPlugin = "postcss-mangle-tailwindcss-plugin";
186
- const clonedKey = "__tw_mangle_cloned__";
187
193
  function isVueScoped(s) {
188
194
  if (s.parent) {
189
195
  const index = s.parent.nodes.indexOf(s);
@@ -197,34 +203,33 @@ function isVueScoped(s) {
197
203
  return false;
198
204
  }
199
205
  const transformSelectorPostcssPlugin = function(options) {
200
- const { ignoreVueScoped, replaceMap, ctx } = defu(options, {
206
+ const { ignoreVueScoped, ctx } = defu(options, {
201
207
  ignoreVueScoped: true
202
208
  });
209
+ const replaceMap = ctx.replaceMap;
203
210
  return {
204
211
  postcssPlugin,
205
- async Rule(rule) {
206
- if (rule[clonedKey]) {
207
- return;
208
- }
209
- await parser((selectors) => {
210
- selectors.walkClasses((s) => {
211
- if (s.value && replaceMap && replaceMap.has(s.value)) {
212
- if (ignoreVueScoped && isVueScoped(s)) {
213
- return;
214
- }
215
- const v = replaceMap.get(s.value);
216
- if (v) {
217
- if (ctx.isPreserveClass(s.value)) {
218
- const r = rule.cloneBefore();
219
- r[clonedKey] = true;
212
+ Once(root) {
213
+ root.walkRules((rule) => {
214
+ parser((selectors) => {
215
+ selectors.walkClasses((s) => {
216
+ if (s.value && replaceMap && replaceMap.has(s.value)) {
217
+ if (ignoreVueScoped && isVueScoped(s)) {
218
+ return;
219
+ }
220
+ const v = replaceMap.get(s.value);
221
+ if (v) {
222
+ if (ctx.isPreserveClass(s.value)) {
223
+ rule.cloneBefore();
224
+ }
225
+ s.value = v;
220
226
  }
221
- s.value = v;
222
227
  }
223
- }
228
+ });
229
+ }).transformSync(rule, {
230
+ lossless: false,
231
+ updateSelector: true
224
232
  });
225
- }).transform(rule, {
226
- lossless: false,
227
- updateSelector: true
228
233
  });
229
234
  }
230
235
  };
@@ -240,121 +245,10 @@ function cssHandler(rawSource, options) {
240
245
  });
241
246
  }
242
247
 
243
- ({
244
- HTML: html.NS.HTML,
245
- XML: html.NS.XML,
246
- MATHML: html.NS.MATHML,
247
- SVG: html.NS.SVG,
248
- XLINK: html.NS.XLINK,
249
- XMLNS: html.NS.XMLNS
250
- });
251
-
252
- /**
253
- * Determines if a given node is a document or not
254
- * @param {Node} node Node to test
255
- * @return {boolean}
256
- */
257
- function isDocument(node) {
258
- return node.nodeName === '#document';
259
- }
260
- /**
261
- * Determines if a given node is a document fragment or not
262
- * @param {Node} node Node to test
263
- * @return {boolean}
264
- */
265
- function isDocumentFragment(node) {
266
- return node.nodeName === '#document-fragment';
267
- }
268
- /**
269
- * Determines if a given node is a template node or not
270
- * @param {Node} node Node to test
271
- * @return {boolean}
272
- */
273
- function isTemplateNode(node) {
274
- return node.nodeName === 'template';
275
- }
276
- const isElementNode = defaultTreeAdapter.isElementNode;
277
- const isCommentNode = defaultTreeAdapter.isCommentNode;
278
- const isDocumentTypeNode = defaultTreeAdapter.isDocumentTypeNode;
279
- const isTextNode = defaultTreeAdapter.isTextNode;
280
- /**
281
- * Determines if a given node is a parent or not
282
- * @param {Node} node Node to test
283
- * @return {boolean}
284
- */
285
- function isParentNode(node) {
286
- return (isDocument(node) ||
287
- isDocumentFragment(node) ||
288
- isElementNode(node) ||
289
- isTemplateNode(node));
290
- }
291
-
292
- defaultTreeAdapter.appendChild;
293
-
294
- /**
295
- * Traverses the tree of a given node
296
- * @param {Node} node Node to traverse
297
- * @param {Visitor} visitor Visitor to apply
298
- * @param {ParentNode=} parent Parent node of the current node
299
- * @return {void}
300
- */
301
- function traverse(node, visitor, parent) {
302
- const shouldVisitChildren = typeof visitor['pre:node'] !== 'function' ||
303
- visitor['pre:node'](node, parent) !== false;
304
- if (shouldVisitChildren && isParentNode(node)) {
305
- for (const child of node.childNodes) {
306
- traverse(child, visitor, node);
307
- }
308
- }
309
- if (typeof visitor.node === 'function') {
310
- visitor.node(node, parent);
311
- }
312
- if (typeof visitor.document === 'function' && isDocument(node)) {
313
- visitor.document(node);
314
- }
315
- if (typeof visitor.documentFragment === 'function' &&
316
- isDocumentFragment(node)) {
317
- visitor.documentFragment(node, parent);
318
- }
319
- if (typeof visitor.element === 'function' && isElementNode(node)) {
320
- visitor.element(node, parent);
321
- }
322
- if (typeof visitor.template === 'function' && isTemplateNode(node)) {
323
- visitor.template(node, parent);
324
- }
325
- if (typeof visitor.comment === 'function' && isCommentNode(node)) {
326
- visitor.comment(node, parent);
327
- }
328
- if (typeof visitor.text === 'function' && isTextNode(node)) {
329
- visitor.text(node, parent);
330
- }
331
- if (typeof visitor.documentType === 'function' && isDocumentTypeNode(node)) {
332
- visitor.documentType(node, parent);
333
- }
334
- }
335
-
336
- function htmlHandler(rawSource, options) {
337
- const { replaceMap, ctx } = options;
338
- const fragment = parse(rawSource);
339
- traverse(fragment, {
340
- element(node) {
341
- const attribute = node.attrs.find((x) => x.name === "class");
342
- if (attribute) {
343
- const array = splitCode(attribute.value, {
344
- splitQuote: false
345
- });
346
- for (const v of array) {
347
- if (replaceMap.has(v)) {
348
- attribute.value = attribute.value.replace(makeRegex(v), ctx.classGenerator.generateClassName(v).name);
349
- }
350
- }
351
- }
352
- }
353
- });
354
- return serialize(fragment);
248
+ function _interopDefaultCompat(e) {
249
+ return e && typeof e === "object" && "default" in e ? e.default : e;
355
250
  }
356
-
357
- const isProd = () => process.env.NODE_ENV === "production";
251
+ const traverse = _interopDefaultCompat(_babelTraverse);
358
252
 
359
253
  function between(x, min, max, included = false) {
360
254
  if (typeof x !== "number") {
@@ -364,7 +258,8 @@ function between(x, min, max, included = false) {
364
258
  }
365
259
 
366
260
  function handleValue$1(options) {
367
- const { ctx, id, path, magicString, raw, replaceMap, offset = 0, escape = false, markedArray } = options;
261
+ const { ctx, id, path, magicString, raw, offset = 0, escape = false, markedArray } = options;
262
+ const { replaceMap } = ctx;
368
263
  const node = path.node;
369
264
  let value = raw;
370
265
  for (const [s, e] of markedArray) {
@@ -377,7 +272,7 @@ function handleValue$1(options) {
377
272
  if (replaceMap.has(str)) {
378
273
  ctx.addToUsedBy(str, id);
379
274
  const v = replaceMap.get(str);
380
- if (v) {
275
+ if (v && typeof v === "string") {
381
276
  value = value.replaceAll(str, v);
382
277
  }
383
278
  }
@@ -390,72 +285,15 @@ function handleValue$1(options) {
390
285
  }
391
286
  }
392
287
  }
393
- const JsPlugin = declare((api, options) => {
394
- api.assertVersion(7);
395
- const { magicString, replaceMap, id, ctx, markedArray } = options;
396
- return {
397
- visitor: {
398
- StringLiteral: {
399
- exit(p) {
400
- const opts = {
401
- ctx,
402
- id,
403
- magicString,
404
- path: p,
405
- raw: p.node.value,
406
- replaceMap,
407
- offset: 1,
408
- escape: true,
409
- markedArray
410
- };
411
- handleValue$1(opts);
412
- }
413
- },
414
- TemplateElement: {
415
- exit(p) {
416
- const opts = {
417
- ctx,
418
- id,
419
- magicString,
420
- path: p,
421
- raw: p.node.value.raw,
422
- replaceMap,
423
- offset: 0,
424
- escape: false,
425
- markedArray
426
- };
427
- handleValue$1(opts);
428
- }
429
- }
430
- }
431
- };
432
- });
433
- function transformSync(ast, code, plugins, filename) {
434
- babel.transformFromAstSync(ast, code, {
435
- presets: loadPresets(),
436
- plugins,
437
- filename
438
- });
439
- }
440
- function loadPresets() {
441
- return [
442
- [
443
- require("@babel/preset-typescript"),
444
- {
445
- allExtensions: true,
446
- isTSX: true
447
- }
448
- ]
449
- ];
450
- }
451
288
  function preProcessJs(options) {
452
- const { code, replaceMap, id, ctx } = options;
289
+ const { code, id, ctx } = options;
290
+ const { replaceMap } = ctx;
453
291
  const magicString = typeof code === "string" ? new MagicString(code) : code;
454
292
  let ast;
455
293
  try {
456
- const file = babel.parseSync(magicString.original, {
294
+ const file = parse(magicString.original, {
457
295
  sourceType: "unambiguous",
458
- presets: loadPresets()
296
+ plugins: ["typescript", "jsx"]
459
297
  });
460
298
  if (file) {
461
299
  ast = file;
@@ -466,7 +304,7 @@ function preProcessJs(options) {
466
304
  return code.toString();
467
305
  }
468
306
  const markedArray = [];
469
- babel.traverse(ast, {
307
+ traverse(ast, {
470
308
  CallExpression: {
471
309
  enter(p) {
472
310
  const callee = p.get("callee");
@@ -502,29 +340,41 @@ function preProcessJs(options) {
502
340
  });
503
341
  }
504
342
  }
505
- }
506
- });
507
- transformSync(
508
- ast,
509
- magicString.original,
510
- [
511
- [
512
- JsPlugin,
513
- {
514
- magicString,
515
- replaceMap,
343
+ },
344
+ StringLiteral: {
345
+ exit(p) {
346
+ handleValue$1({
347
+ ctx,
516
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({
517
361
  ctx,
362
+ id,
363
+ magicString,
364
+ path: p,
365
+ raw: p.node.value.raw,
366
+ offset: 0,
367
+ escape: false,
518
368
  markedArray
519
- }
520
- ]
521
- ],
522
- id
523
- );
369
+ });
370
+ }
371
+ }
372
+ });
524
373
  return magicString.toString();
525
374
  }
526
375
  function preProcessRawCode(options) {
527
- const { code, replaceMap, ctx } = options;
376
+ const { code, ctx } = options;
377
+ const { replaceMap } = ctx;
528
378
  const magicString = typeof code === "string" ? new MagicString(code) : code;
529
379
  const markArr = [];
530
380
  for (const regex of ctx.preserveFunctionRegexs) {
@@ -537,10 +387,10 @@ function preProcessRawCode(options) {
537
387
  for (const regExpMatch of allArr) {
538
388
  let ast;
539
389
  try {
540
- ast = babel.parseSync(regExpMatch[0], {
390
+ ast = parse(regExpMatch[0], {
541
391
  sourceType: "unambiguous"
542
392
  });
543
- ast && babel.traverse(ast, {
393
+ ast && traverse(ast, {
544
394
  StringLiteral: {
545
395
  enter(p) {
546
396
  const arr2 = sort(splitCode(p.node.value)).desc((x) => x.length);
@@ -580,7 +430,7 @@ function preProcessRawCode(options) {
580
430
  break;
581
431
  }
582
432
  }
583
- if (shouldUpdate) {
433
+ if (shouldUpdate && typeof value === "string") {
584
434
  magicString.update(start, end, value);
585
435
  markArr.push([start, end]);
586
436
  }
@@ -589,13 +439,14 @@ function preProcessRawCode(options) {
589
439
  return magicString.toString();
590
440
  }
591
441
 
592
- function handleValue(raw, node, options) {
593
- const { replaceMap, ctx, splitQuote = true } = options;
594
- const clsGen = ctx.classGenerator;
442
+ function handleValue(raw, node, options, ms, offset, escape) {
443
+ const { ctx, splitQuote = true } = options;
444
+ const { replaceMap, classGenerator: clsGen } = ctx;
595
445
  const array = splitCode(raw, {
596
446
  splitQuote
597
447
  });
598
448
  let rawString = raw;
449
+ let needUpdate = false;
599
450
  for (const v of array) {
600
451
  if (replaceMap.has(v)) {
601
452
  let ignoreFlag = false;
@@ -604,58 +455,116 @@ function handleValue(raw, node, options) {
604
455
  }
605
456
  if (!ignoreFlag) {
606
457
  rawString = rawString.replace(makeRegex(v), clsGen.generateClassName(v).name);
458
+ needUpdate = true;
607
459
  }
608
460
  }
609
461
  }
462
+ if (needUpdate && typeof node.start === "number" && typeof node.end === "number") {
463
+ const start = node.start + offset;
464
+ const end = node.end - offset;
465
+ if (start < end && raw !== rawString) {
466
+ ms.update(start, end, escape ? jsStringEscape(rawString) : rawString);
467
+ }
468
+ }
610
469
  return rawString;
611
470
  }
612
471
  function jsHandler(rawSource, options) {
613
- const result = transformSync$1(rawSource, {
614
- babelrc: false,
615
- ast: true,
616
- plugins: [
617
- () => {
618
- return {
619
- visitor: {
620
- StringLiteral: {
621
- enter(p) {
622
- const n = p.node;
623
- n.value = handleValue(n.value, n, options);
624
- }
625
- },
626
- TemplateElement: {
627
- enter(p) {
628
- const n = p.node;
629
- n.value.raw = handleValue(n.value.raw, n, options);
630
- }
631
- },
632
- CallExpression: {
633
- enter(p) {
634
- const calleePath = p.get("callee");
635
- if (calleePath.isIdentifier() && calleePath.node.name === "eval") {
636
- p.traverse({
637
- StringLiteral: {
638
- enter(s) {
639
- const res = jsHandler(s.node.value, options);
640
- if (res.code) {
641
- s.node.value = res.code;
642
- }
643
- }
644
- }
645
- });
646
- }
647
- }
648
- }
649
- // noScope: true
472
+ const ms = typeof rawSource === "string" ? new MagicString(rawSource) : rawSource;
473
+ const ast = parse(ms.original, {
474
+ sourceType: "unambiguous",
475
+ plugins: ["typescript", "jsx"]
476
+ });
477
+ traverse(ast, {
478
+ StringLiteral: {
479
+ enter(p) {
480
+ const n = p.node;
481
+ handleValue(n.value, n, options, ms, 1, true);
482
+ }
483
+ },
484
+ TemplateElement: {
485
+ enter(p) {
486
+ const n = p.node;
487
+ handleValue(n.value.raw, n, options, ms, 0, false);
488
+ }
489
+ }
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
+ });
509
+ return {
510
+ code: ms.toString(),
511
+ get map() {
512
+ return ms.generateMap();
513
+ }
514
+ };
515
+ }
516
+
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);
650
531
  }
651
- };
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
+ }
652
542
  }
653
- ],
654
- minified: options.minified ?? isProd(),
655
- sourceMaps: false,
656
- configFile: false
543
+ }
657
544
  });
658
- return result;
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();
659
568
  }
660
569
 
661
- export { Context, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode };
570
+ export { Context, cssHandler, handleValue, htmlHandler, jsHandler, preProcessJs, preProcessRawCode, vueHandler };