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