tailwindcss-patch 8.4.3 → 8.5.1

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.
@@ -9,6 +9,9 @@ import fs from "fs-extra";
9
9
  function isErrnoException(error) {
10
10
  return error instanceof Error && typeof error.code === "string";
11
11
  }
12
+ function isAccessDenied(error) {
13
+ return isErrnoException(error) && Boolean(error.code && ["EPERM", "EBUSY", "EACCES"].includes(error.code));
14
+ }
12
15
  var CacheStore = class {
13
16
  constructor(options) {
14
17
  this.options = options;
@@ -26,17 +29,22 @@ var CacheStore = class {
26
29
  async replaceCacheFile(tempPath) {
27
30
  try {
28
31
  await fs.rename(tempPath, this.options.path);
32
+ return true;
29
33
  } catch (error) {
30
34
  if (isErrnoException(error) && (error.code === "EEXIST" || error.code === "EPERM")) {
31
35
  try {
32
36
  await fs.remove(this.options.path);
33
37
  } catch (removeError) {
38
+ if (isAccessDenied(removeError)) {
39
+ logger_default.debug("Tailwind class cache locked or read-only, skipping update.", removeError);
40
+ return false;
41
+ }
34
42
  if (!isErrnoException(removeError) || removeError.code !== "ENOENT") {
35
43
  throw removeError;
36
44
  }
37
45
  }
38
46
  await fs.rename(tempPath, this.options.path);
39
- return;
47
+ return true;
40
48
  }
41
49
  throw error;
42
50
  }
@@ -44,17 +52,22 @@ var CacheStore = class {
44
52
  replaceCacheFileSync(tempPath) {
45
53
  try {
46
54
  fs.renameSync(tempPath, this.options.path);
55
+ return true;
47
56
  } catch (error) {
48
57
  if (isErrnoException(error) && (error.code === "EEXIST" || error.code === "EPERM")) {
49
58
  try {
50
59
  fs.removeSync(this.options.path);
51
60
  } catch (removeError) {
61
+ if (isAccessDenied(removeError)) {
62
+ logger_default.debug("Tailwind class cache locked or read-only, skipping update.", removeError);
63
+ return false;
64
+ }
52
65
  if (!isErrnoException(removeError) || removeError.code !== "ENOENT") {
53
66
  throw removeError;
54
67
  }
55
68
  }
56
69
  fs.renameSync(tempPath, this.options.path);
57
- return;
70
+ return true;
58
71
  }
59
72
  throw error;
60
73
  }
@@ -79,8 +92,12 @@ var CacheStore = class {
79
92
  try {
80
93
  await this.ensureDir();
81
94
  await fs.writeJSON(tempPath, Array.from(data));
82
- await this.replaceCacheFile(tempPath);
83
- return this.options.path;
95
+ const replaced = await this.replaceCacheFile(tempPath);
96
+ if (replaced) {
97
+ return this.options.path;
98
+ }
99
+ await this.cleanupTempFile(tempPath);
100
+ return void 0;
84
101
  } catch (error) {
85
102
  await this.cleanupTempFile(tempPath);
86
103
  logger_default.error("Unable to persist Tailwind class cache", error);
@@ -95,8 +112,12 @@ var CacheStore = class {
95
112
  try {
96
113
  this.ensureDirSync();
97
114
  fs.writeJSONSync(tempPath, Array.from(data));
98
- this.replaceCacheFileSync(tempPath);
99
- return this.options.path;
115
+ const replaced = this.replaceCacheFileSync(tempPath);
116
+ if (replaced) {
117
+ return this.options.path;
118
+ }
119
+ this.cleanupTempFileSync(tempPath);
120
+ return void 0;
100
121
  } catch (error) {
101
122
  this.cleanupTempFileSync(tempPath);
102
123
  logger_default.error("Unable to persist Tailwind class cache", error);
@@ -520,372 +541,69 @@ function normalizeOptions(options = {}) {
520
541
  };
521
542
  }
522
543
 
523
- // src/runtime/class-collector.ts
524
- import process4 from "process";
525
- import fs3 from "fs-extra";
526
- import path3 from "pathe";
544
+ // src/patching/status.ts
545
+ import * as t4 from "@babel/types";
546
+ import fs4 from "fs-extra";
547
+ import path4 from "pathe";
527
548
 
528
- // src/utils.ts
529
- function isObject(val) {
530
- return val !== null && typeof val === "object" && Array.isArray(val) === false;
549
+ // src/babel/index.ts
550
+ import _babelGenerate from "@babel/generator";
551
+ import _babelTraverse from "@babel/traverse";
552
+ import { parse, parseExpression } from "@babel/parser";
553
+ function _interopDefaultCompat(e) {
554
+ return e && typeof e === "object" && "default" in e ? e.default : e;
531
555
  }
532
- function spliceChangesIntoString(str, changes) {
533
- if (!changes[0]) {
534
- return str;
556
+ var generate = _interopDefaultCompat(_babelGenerate);
557
+ var traverse = _interopDefaultCompat(_babelTraverse);
558
+
559
+ // src/patching/operations/export-context/postcss-v2.ts
560
+ import * as t from "@babel/types";
561
+ var IDENTIFIER_RE = /^[A-Z_$][\w$]*$/i;
562
+ function toIdentifierName(property) {
563
+ if (!property) {
564
+ return "contextRef";
535
565
  }
536
- changes.sort((a, b) => {
537
- return a.end - b.end || a.start - b.start;
538
- });
539
- let result = "";
540
- let previous = changes[0];
541
- result += str.slice(0, previous.start);
542
- result += previous.replacement;
543
- for (let i = 1; i < changes.length; ++i) {
544
- const change = changes[i];
545
- result += str.slice(previous.end, change.start);
546
- result += change.replacement;
547
- previous = change;
566
+ const sanitized = property.replace(/[^\w$]/gu, "_");
567
+ if (/^\d/.test(sanitized)) {
568
+ return `_${sanitized}`;
548
569
  }
549
- result += str.slice(previous.end);
550
- return result;
570
+ return sanitized || "contextRef";
551
571
  }
552
-
553
- // src/runtime/class-collector.ts
554
- function collectClassesFromContexts(contexts, filter) {
555
- const set = /* @__PURE__ */ new Set();
556
- for (const context of contexts) {
557
- if (!isObject(context) || !context.classCache) {
558
- continue;
559
- }
560
- for (const key of context.classCache.keys()) {
561
- const className = key.toString();
562
- if (filter(className)) {
563
- set.add(className);
564
- }
565
- }
572
+ function createExportsMember(property) {
573
+ if (IDENTIFIER_RE.test(property)) {
574
+ return t.memberExpression(t.identifier("exports"), t.identifier(property));
566
575
  }
567
- return set;
576
+ return t.memberExpression(t.identifier("exports"), t.stringLiteral(property), true);
568
577
  }
569
- async function collectClassesFromTailwindV4(options) {
570
- const set = /* @__PURE__ */ new Set();
571
- const v4Options = options.tailwind.v4;
572
- if (!v4Options) {
573
- return set;
574
- }
575
- const toAbsolute = (value) => {
576
- if (!value) {
577
- return void 0;
578
- }
579
- return path3.isAbsolute(value) ? value : path3.resolve(options.projectRoot, value);
580
- };
581
- const resolvedConfiguredBase = toAbsolute(v4Options.configuredBase);
582
- const resolvedDefaultBase = toAbsolute(v4Options.base) ?? process4.cwd();
583
- const resolveSources = (base) => {
584
- if (!v4Options.sources?.length) {
585
- return void 0;
586
- }
587
- return v4Options.sources.map((source) => ({
588
- base: source.base ?? base,
589
- pattern: source.pattern,
590
- negated: source.negated
591
- }));
592
- };
593
- if (v4Options.cssEntries.length > 0) {
594
- for (const entry of v4Options.cssEntries) {
595
- const filePath = path3.isAbsolute(entry) ? entry : path3.resolve(options.projectRoot, entry);
596
- if (!await fs3.pathExists(filePath)) {
597
- continue;
578
+ function transformProcessTailwindFeaturesReturnContextV2(content) {
579
+ const ast = parse(content, {
580
+ sourceType: "unambiguous"
581
+ });
582
+ let hasPatched = false;
583
+ traverse(ast, {
584
+ FunctionDeclaration(path11) {
585
+ const node = path11.node;
586
+ if (node.id?.name !== "processTailwindFeatures" || node.body.body.length !== 1 || !t.isReturnStatement(node.body.body[0])) {
587
+ return;
598
588
  }
599
- const css = await fs3.readFile(filePath, "utf8");
600
- const entryDir = path3.dirname(filePath);
601
- const baseForEntry = resolvedConfiguredBase ?? entryDir;
602
- const sources = resolveSources(baseForEntry);
603
- const candidates = await extractValidCandidates({
604
- cwd: options.projectRoot,
605
- base: baseForEntry,
606
- css,
607
- sources
608
- });
609
- for (const candidate of candidates) {
610
- if (options.filter(candidate)) {
611
- set.add(candidate);
612
- }
589
+ const returnStatement3 = node.body.body[0];
590
+ if (!t.isFunctionExpression(returnStatement3.argument)) {
591
+ return;
613
592
  }
614
- }
615
- } else {
616
- const baseForCss = resolvedConfiguredBase ?? resolvedDefaultBase;
617
- const sources = resolveSources(baseForCss);
618
- const candidates = await extractValidCandidates({
619
- cwd: options.projectRoot,
620
- base: baseForCss,
621
- css: v4Options.css,
622
- sources
623
- });
624
- for (const candidate of candidates) {
625
- if (options.filter(candidate)) {
626
- set.add(candidate);
593
+ const body = returnStatement3.argument.body.body;
594
+ const lastStatement = body[body.length - 1];
595
+ const alreadyReturnsContext = Boolean(
596
+ t.isReturnStatement(lastStatement) && t.isIdentifier(lastStatement.argument) && lastStatement.argument.name === "context"
597
+ );
598
+ hasPatched = alreadyReturnsContext;
599
+ if (!alreadyReturnsContext) {
600
+ body.push(t.returnStatement(t.identifier("context")));
627
601
  }
628
602
  }
629
- }
630
- return set;
631
- }
632
-
633
- // src/runtime/context-registry.ts
634
- import { createRequire } from "module";
635
- import fs4 from "fs-extra";
636
- import path4 from "pathe";
637
- var require2 = createRequire(import.meta.url);
638
- function resolveRuntimeEntry(packageInfo, majorVersion) {
639
- const root = packageInfo.rootPath;
640
- if (majorVersion === 2) {
641
- const jitIndex = path4.join(root, "lib/jit/index.js");
642
- if (fs4.existsSync(jitIndex)) {
643
- return jitIndex;
644
- }
645
- } else if (majorVersion === 3) {
646
- const plugin = path4.join(root, "lib/plugin.js");
647
- const index = path4.join(root, "lib/index.js");
648
- if (fs4.existsSync(plugin)) {
649
- return plugin;
650
- }
651
- if (fs4.existsSync(index)) {
652
- return index;
653
- }
654
- }
655
- return void 0;
656
- }
657
- function loadRuntimeContexts(packageInfo, majorVersion, refProperty) {
658
- if (majorVersion === 4) {
659
- return [];
660
- }
661
- const entry = resolveRuntimeEntry(packageInfo, majorVersion);
662
- if (!entry) {
663
- return [];
664
- }
665
- const moduleExports = require2(entry);
666
- if (!moduleExports) {
667
- return [];
668
- }
669
- const ref = moduleExports[refProperty];
670
- if (!ref) {
671
- return [];
672
- }
673
- if (Array.isArray(ref)) {
674
- return ref;
675
- }
676
- if (typeof ref === "object" && Array.isArray(ref.value)) {
677
- return ref.value;
678
- }
679
- return [];
680
- }
681
-
682
- // src/runtime/process-tailwindcss.ts
683
- import { createRequire as createRequire2 } from "module";
684
- import path5 from "pathe";
685
- import postcss from "postcss";
686
- import { loadConfig } from "tailwindcss-config";
687
- var require3 = createRequire2(import.meta.url);
688
- async function resolveConfigPath(options) {
689
- if (options.config && path5.isAbsolute(options.config)) {
690
- return options.config;
691
- }
692
- const result = await loadConfig({ cwd: options.cwd });
693
- if (!result) {
694
- throw new Error(`Unable to locate Tailwind CSS config from ${options.cwd}`);
695
- }
696
- return result.filepath;
697
- }
698
- async function runTailwindBuild(options) {
699
- const configPath = await resolveConfigPath(options);
700
- const pluginName = options.postcssPlugin ?? (options.majorVersion === 4 ? "@tailwindcss/postcss" : "tailwindcss");
701
- if (options.majorVersion === 4) {
702
- return postcss([
703
- require3(pluginName)({
704
- config: configPath
705
- })
706
- ]).process("@import 'tailwindcss';", {
707
- from: void 0
708
- });
709
- }
710
- return postcss([
711
- require3(pluginName)({
712
- config: configPath
713
- })
714
- ]).process("@tailwind base;@tailwind components;@tailwind utilities;", {
715
- from: void 0
716
603
  });
717
- }
718
-
719
- // src/api/tailwindcss-patcher.ts
720
- import process5 from "process";
721
- import fs7 from "fs-extra";
722
- import { getPackageInfoSync } from "local-pkg";
723
- import path8 from "pathe";
724
- import { coerce } from "semver";
725
-
726
- // src/options/legacy.ts
727
- function normalizeLegacyFeatures(patch) {
728
- const apply = patch?.applyPatches;
729
- const extend = apply?.extendLengthUnits;
730
- let extendOption = false;
731
- if (extend && typeof extend === "object") {
732
- extendOption = {
733
- ...extend,
734
- enabled: true
735
- };
736
- } else if (extend === true) {
737
- extendOption = {
738
- enabled: true,
739
- units: ["rpx"],
740
- overwrite: patch?.overwrite
741
- };
742
- }
743
604
  return {
744
- exposeContext: apply?.exportContext ?? true,
745
- extendLengthUnits: extendOption
746
- };
747
- }
748
- function fromLegacyOptions(options) {
749
- if (!options) {
750
- return {};
751
- }
752
- const patch = options.patch;
753
- const features = normalizeLegacyFeatures(patch);
754
- const output = patch?.output;
755
- const tailwindConfig = patch?.tailwindcss;
756
- const tailwindVersion = tailwindConfig?.version;
757
- const tailwindV2 = tailwindConfig?.v2;
758
- const tailwindV3 = tailwindConfig?.v3;
759
- const tailwindV4 = tailwindConfig?.v4;
760
- const tailwindConfigPath = tailwindV3?.config ?? tailwindV2?.config;
761
- const tailwindCwd = tailwindV3?.cwd ?? tailwindV2?.cwd ?? patch?.cwd;
762
- return {
763
- cwd: patch?.cwd,
764
- overwrite: patch?.overwrite,
765
- filter: patch?.filter,
766
- cache: typeof options.cache === "boolean" ? options.cache : options.cache ? {
767
- ...options.cache,
768
- enabled: options.cache.enabled ?? true
769
- } : void 0,
770
- output: output ? {
771
- file: output.filename,
772
- pretty: output.loose ? 2 : false,
773
- removeUniversalSelector: output.removeUniversalSelector
774
- } : void 0,
775
- tailwind: {
776
- packageName: patch?.packageName,
777
- version: tailwindVersion,
778
- resolve: patch?.resolve,
779
- config: tailwindConfigPath,
780
- cwd: tailwindCwd,
781
- v2: tailwindV2,
782
- v3: tailwindV3,
783
- v4: tailwindV4
784
- },
785
- features: {
786
- exposeContext: features.exposeContext,
787
- extendLengthUnits: features.extendLengthUnits
788
- }
789
- };
790
- }
791
- function fromUnifiedConfig(registry) {
792
- if (!registry) {
793
- return {};
794
- }
795
- const tailwind = registry.tailwind;
796
- const output = registry.output;
797
- const pretty = (() => {
798
- if (output?.pretty === void 0) {
799
- return void 0;
800
- }
801
- if (typeof output.pretty === "boolean") {
802
- return output.pretty ? 2 : false;
803
- }
804
- return output.pretty;
805
- })();
806
- return {
807
- output: output ? {
808
- file: output.file,
809
- pretty,
810
- removeUniversalSelector: output.stripUniversalSelector
811
- } : void 0,
812
- tailwind: tailwind ? {
813
- version: tailwind.version,
814
- packageName: tailwind.package,
815
- resolve: tailwind.resolve,
816
- config: tailwind.config,
817
- cwd: tailwind.cwd,
818
- v2: tailwind.legacy,
819
- v3: tailwind.classic,
820
- v4: tailwind.next
821
- } : void 0
822
- };
823
- }
824
-
825
- // src/patching/operations/export-context/index.ts
826
- import fs5 from "fs-extra";
827
- import path6 from "pathe";
828
-
829
- // src/patching/operations/export-context/postcss-v2.ts
830
- import * as t from "@babel/types";
831
-
832
- // src/babel/index.ts
833
- import _babelGenerate from "@babel/generator";
834
- import _babelTraverse from "@babel/traverse";
835
- import { parse, parseExpression } from "@babel/parser";
836
- function _interopDefaultCompat(e) {
837
- return e && typeof e === "object" && "default" in e ? e.default : e;
838
- }
839
- var generate = _interopDefaultCompat(_babelGenerate);
840
- var traverse = _interopDefaultCompat(_babelTraverse);
841
-
842
- // src/patching/operations/export-context/postcss-v2.ts
843
- var IDENTIFIER_RE = /^[A-Z_$][\w$]*$/i;
844
- function toIdentifierName(property) {
845
- if (!property) {
846
- return "contextRef";
847
- }
848
- const sanitized = property.replace(/[^\w$]/gu, "_");
849
- if (/^\d/.test(sanitized)) {
850
- return `_${sanitized}`;
851
- }
852
- return sanitized || "contextRef";
853
- }
854
- function createExportsMember(property) {
855
- if (IDENTIFIER_RE.test(property)) {
856
- return t.memberExpression(t.identifier("exports"), t.identifier(property));
857
- }
858
- return t.memberExpression(t.identifier("exports"), t.stringLiteral(property), true);
859
- }
860
- function transformProcessTailwindFeaturesReturnContextV2(content) {
861
- const ast = parse(content, {
862
- sourceType: "unambiguous"
863
- });
864
- let hasPatched = false;
865
- traverse(ast, {
866
- FunctionDeclaration(path10) {
867
- const node = path10.node;
868
- if (node.id?.name !== "processTailwindFeatures" || node.body.body.length !== 1 || !t.isReturnStatement(node.body.body[0])) {
869
- return;
870
- }
871
- const returnStatement3 = node.body.body[0];
872
- if (!t.isFunctionExpression(returnStatement3.argument)) {
873
- return;
874
- }
875
- const body = returnStatement3.argument.body.body;
876
- const lastStatement = body[body.length - 1];
877
- const alreadyReturnsContext = Boolean(
878
- t.isReturnStatement(lastStatement) && t.isIdentifier(lastStatement.argument) && lastStatement.argument.name === "context"
879
- );
880
- hasPatched = alreadyReturnsContext;
881
- if (!alreadyReturnsContext) {
882
- body.push(t.returnStatement(t.identifier("context")));
883
- }
884
- }
885
- });
886
- return {
887
- code: hasPatched ? content : generate(ast).code,
888
- hasPatched
605
+ code: hasPatched ? content : generate(ast).code,
606
+ hasPatched
889
607
  };
890
608
  }
891
609
  function transformPostcssPluginV2(content, options) {
@@ -895,8 +613,8 @@ function transformPostcssPluginV2(content, options) {
895
613
  const ast = parse(content);
896
614
  let hasPatched = false;
897
615
  traverse(ast, {
898
- Program(path10) {
899
- const program = path10.node;
616
+ Program(path11) {
617
+ const program = path11.node;
900
618
  const index = program.body.findIndex((statement) => {
901
619
  return t.isFunctionDeclaration(statement) && statement.id?.name === "_default";
902
620
  });
@@ -930,11 +648,11 @@ function transformPostcssPluginV2(content, options) {
930
648
  );
931
649
  }
932
650
  },
933
- FunctionDeclaration(path10) {
651
+ FunctionDeclaration(path11) {
934
652
  if (hasPatched) {
935
653
  return;
936
654
  }
937
- const fn = path10.node;
655
+ const fn = path11.node;
938
656
  if (fn.id?.name !== "_default") {
939
657
  return;
940
658
  }
@@ -1023,8 +741,8 @@ function transformProcessTailwindFeaturesReturnContext(content) {
1023
741
  const ast = parse(content);
1024
742
  let hasPatched = false;
1025
743
  traverse(ast, {
1026
- FunctionDeclaration(path10) {
1027
- const node = path10.node;
744
+ FunctionDeclaration(path11) {
745
+ const node = path11.node;
1028
746
  if (node.id?.name !== "processTailwindFeatures" || node.body.body.length !== 1) {
1029
747
  return;
1030
748
  }
@@ -1056,8 +774,8 @@ function transformPostcssPlugin(content, { refProperty }) {
1056
774
  const valueMember = t2.memberExpression(refIdentifier, t2.identifier("value"));
1057
775
  let hasPatched = false;
1058
776
  traverse(ast, {
1059
- Program(path10) {
1060
- const program = path10.node;
777
+ Program(path11) {
778
+ const program = path11.node;
1061
779
  const index = program.body.findIndex((statement) => {
1062
780
  return t2.isExpressionStatement(statement) && t2.isAssignmentExpression(statement.expression) && t2.isMemberExpression(statement.expression.left) && t2.isFunctionExpression(statement.expression.right) && statement.expression.right.id?.name === "tailwindcss";
1063
781
  });
@@ -1095,11 +813,11 @@ function transformPostcssPlugin(content, { refProperty }) {
1095
813
  );
1096
814
  }
1097
815
  },
1098
- FunctionExpression(path10) {
816
+ FunctionExpression(path11) {
1099
817
  if (hasPatched) {
1100
818
  return;
1101
819
  }
1102
- const fn = path10.node;
820
+ const fn = path11.node;
1103
821
  if (fn.id?.name !== "tailwindcss" || fn.body.body.length !== 1) {
1104
822
  return;
1105
823
  }
@@ -1161,19 +879,664 @@ function transformPostcssPlugin(content, { refProperty }) {
1161
879
  )
1162
880
  );
1163
881
  }
1164
- });
882
+ });
883
+ return {
884
+ code: hasPatched ? content : generate(ast).code,
885
+ hasPatched
886
+ };
887
+ }
888
+
889
+ // src/patching/operations/extend-length-units.ts
890
+ import * as t3 from "@babel/types";
891
+ import fs3 from "fs-extra";
892
+ import path3 from "pathe";
893
+
894
+ // src/utils.ts
895
+ function isObject(val) {
896
+ return val !== null && typeof val === "object" && Array.isArray(val) === false;
897
+ }
898
+ function spliceChangesIntoString(str, changes) {
899
+ if (!changes[0]) {
900
+ return str;
901
+ }
902
+ changes.sort((a, b) => {
903
+ return a.end - b.end || a.start - b.start;
904
+ });
905
+ let result = "";
906
+ let previous = changes[0];
907
+ result += str.slice(0, previous.start);
908
+ result += previous.replacement;
909
+ for (let i = 1; i < changes.length; ++i) {
910
+ const change = changes[i];
911
+ result += str.slice(previous.end, change.start);
912
+ result += change.replacement;
913
+ previous = change;
914
+ }
915
+ result += str.slice(previous.end);
916
+ return result;
917
+ }
918
+
919
+ // src/patching/operations/extend-length-units.ts
920
+ function updateLengthUnitsArray(content, options) {
921
+ const { variableName = "lengthUnits", units } = options;
922
+ const ast = parse(content);
923
+ let arrayRef;
924
+ let changed = false;
925
+ traverse(ast, {
926
+ Identifier(path11) {
927
+ if (path11.node.name === variableName && t3.isVariableDeclarator(path11.parent) && t3.isArrayExpression(path11.parent.init)) {
928
+ arrayRef = path11.parent.init;
929
+ const existing = new Set(
930
+ path11.parent.init.elements.map((element) => t3.isStringLiteral(element) ? element.value : void 0).filter(Boolean)
931
+ );
932
+ for (const unit of units) {
933
+ if (!existing.has(unit)) {
934
+ path11.parent.init.elements = path11.parent.init.elements.map((element) => {
935
+ if (t3.isStringLiteral(element)) {
936
+ return t3.stringLiteral(element.value);
937
+ }
938
+ return element;
939
+ });
940
+ path11.parent.init.elements.push(t3.stringLiteral(unit));
941
+ changed = true;
942
+ }
943
+ }
944
+ }
945
+ }
946
+ });
947
+ return {
948
+ arrayRef,
949
+ changed
950
+ };
951
+ }
952
+ function applyExtendLengthUnitsPatchV3(rootDir, options) {
953
+ if (!options.enabled) {
954
+ return { changed: false, code: void 0 };
955
+ }
956
+ const opts = {
957
+ ...options,
958
+ lengthUnitsFilePath: options.lengthUnitsFilePath ?? "lib/util/dataTypes.js",
959
+ variableName: options.variableName ?? "lengthUnits"
960
+ };
961
+ const dataTypesFilePath = path3.resolve(rootDir, opts.lengthUnitsFilePath);
962
+ const exists = fs3.existsSync(dataTypesFilePath);
963
+ if (!exists) {
964
+ return { changed: false, code: void 0 };
965
+ }
966
+ const content = fs3.readFileSync(dataTypesFilePath, "utf8");
967
+ const { arrayRef, changed } = updateLengthUnitsArray(content, opts);
968
+ if (!arrayRef || !changed) {
969
+ return { changed: false, code: void 0 };
970
+ }
971
+ const { code } = generate(arrayRef, {
972
+ jsescOption: { quotes: "single" }
973
+ });
974
+ if (arrayRef.start != null && arrayRef.end != null) {
975
+ const nextCode = `${content.slice(0, arrayRef.start)}${code}${content.slice(arrayRef.end)}`;
976
+ if (opts.overwrite) {
977
+ const target = opts.destPath ? path3.resolve(opts.destPath) : dataTypesFilePath;
978
+ fs3.writeFileSync(target, nextCode, "utf8");
979
+ logger_default.success("Patched Tailwind CSS length unit list (v3).");
980
+ }
981
+ return {
982
+ changed: true,
983
+ code: nextCode
984
+ };
985
+ }
986
+ return {
987
+ changed: false,
988
+ code: void 0
989
+ };
990
+ }
991
+ function applyExtendLengthUnitsPatchV4(rootDir, options) {
992
+ if (!options.enabled) {
993
+ return { files: [], changed: false };
994
+ }
995
+ const opts = { ...options };
996
+ const distDir = path3.resolve(rootDir, "dist");
997
+ if (!fs3.existsSync(distDir)) {
998
+ return { files: [], changed: false };
999
+ }
1000
+ const entries = fs3.readdirSync(distDir);
1001
+ const chunkNames = entries.filter((entry) => entry.endsWith(".js") || entry.endsWith(".mjs"));
1002
+ const pattern = /\[\s*["']cm["'],\s*["']mm["'],[\w,"']+\]/;
1003
+ const candidates = chunkNames.map((chunkName) => {
1004
+ const file = path3.join(distDir, chunkName);
1005
+ const code = fs3.readFileSync(file, "utf8");
1006
+ const match = pattern.exec(code);
1007
+ if (!match) {
1008
+ return null;
1009
+ }
1010
+ return {
1011
+ file,
1012
+ code,
1013
+ match,
1014
+ hasPatched: false
1015
+ };
1016
+ }).filter((candidate) => candidate !== null);
1017
+ for (const item of candidates) {
1018
+ const { code, file, match } = item;
1019
+ const ast = parse(match[0], { sourceType: "unambiguous" });
1020
+ traverse(ast, {
1021
+ ArrayExpression(path11) {
1022
+ for (const unit of opts.units) {
1023
+ if (path11.node.elements.some((element) => t3.isStringLiteral(element) && element.value === unit)) {
1024
+ item.hasPatched = true;
1025
+ return;
1026
+ }
1027
+ path11.node.elements.push(t3.stringLiteral(unit));
1028
+ }
1029
+ }
1030
+ });
1031
+ if (item.hasPatched) {
1032
+ continue;
1033
+ }
1034
+ const { code: replacement } = generate(ast, { minified: true });
1035
+ const start = match.index ?? 0;
1036
+ const end = start + match[0].length;
1037
+ item.code = spliceChangesIntoString(code, [
1038
+ {
1039
+ start,
1040
+ end,
1041
+ replacement: replacement.endsWith(";") ? replacement.slice(0, -1) : replacement
1042
+ }
1043
+ ]);
1044
+ if (opts.overwrite) {
1045
+ fs3.writeFileSync(file, item.code, "utf8");
1046
+ }
1047
+ }
1048
+ if (candidates.some((file) => !file.hasPatched)) {
1049
+ logger_default.success("Patched Tailwind CSS length unit list (v4).");
1050
+ }
1051
+ return {
1052
+ changed: candidates.some((file) => !file.hasPatched),
1053
+ files: candidates
1054
+ };
1055
+ }
1056
+
1057
+ // src/patching/status.ts
1058
+ function inspectLengthUnitsArray(content, variableName, units) {
1059
+ const ast = parse(content);
1060
+ let found = false;
1061
+ let missingUnits = [];
1062
+ traverse(ast, {
1063
+ Identifier(path11) {
1064
+ if (path11.node.name === variableName && t4.isVariableDeclarator(path11.parent) && t4.isArrayExpression(path11.parent.init)) {
1065
+ found = true;
1066
+ const existing = new Set(
1067
+ path11.parent.init.elements.map((element) => t4.isStringLiteral(element) ? element.value : void 0).filter(Boolean)
1068
+ );
1069
+ missingUnits = units.filter((unit) => !existing.has(unit));
1070
+ path11.stop();
1071
+ }
1072
+ }
1073
+ });
1074
+ return {
1075
+ found,
1076
+ missingUnits
1077
+ };
1078
+ }
1079
+ function checkExposeContextPatch(context) {
1080
+ const { packageInfo, options, majorVersion } = context;
1081
+ const refProperty = options.features.exposeContext.refProperty;
1082
+ if (!options.features.exposeContext.enabled) {
1083
+ return {
1084
+ name: "exposeContext",
1085
+ status: "skipped",
1086
+ reason: "exposeContext feature disabled",
1087
+ files: []
1088
+ };
1089
+ }
1090
+ if (majorVersion === 4) {
1091
+ return {
1092
+ name: "exposeContext",
1093
+ status: "unsupported",
1094
+ reason: "Context export patch is only required for Tailwind v2/v3",
1095
+ files: []
1096
+ };
1097
+ }
1098
+ const checks = [];
1099
+ function inspectFile(relative, transform) {
1100
+ const filePath = path4.resolve(packageInfo.rootPath, relative);
1101
+ if (!fs4.existsSync(filePath)) {
1102
+ checks.push({ relative, exists: false, patched: false });
1103
+ return;
1104
+ }
1105
+ const content = fs4.readFileSync(filePath, "utf8");
1106
+ const { hasPatched } = transform(content);
1107
+ checks.push({
1108
+ relative,
1109
+ exists: true,
1110
+ patched: hasPatched
1111
+ });
1112
+ }
1113
+ if (majorVersion === 3) {
1114
+ inspectFile("lib/processTailwindFeatures.js", transformProcessTailwindFeaturesReturnContext);
1115
+ const pluginCandidates = ["lib/plugin.js", "lib/index.js"];
1116
+ const pluginRelative = pluginCandidates.find((candidate) => fs4.existsSync(path4.resolve(packageInfo.rootPath, candidate)));
1117
+ if (pluginRelative) {
1118
+ inspectFile(pluginRelative, (content) => transformPostcssPlugin(content, { refProperty }));
1119
+ } else {
1120
+ checks.push({ relative: "lib/plugin.js", exists: false, patched: false });
1121
+ }
1122
+ } else {
1123
+ inspectFile("lib/jit/processTailwindFeatures.js", transformProcessTailwindFeaturesReturnContextV2);
1124
+ inspectFile("lib/jit/index.js", (content) => transformPostcssPluginV2(content, { refProperty }));
1125
+ }
1126
+ const files = checks.filter((check) => check.exists).map((check) => check.relative);
1127
+ const missingFiles = checks.filter((check) => !check.exists);
1128
+ const unpatchedFiles = checks.filter((check) => check.exists && !check.patched);
1129
+ const reasons = [];
1130
+ if (missingFiles.length) {
1131
+ reasons.push(`missing files: ${missingFiles.map((item) => item.relative).join(", ")}`);
1132
+ }
1133
+ if (unpatchedFiles.length) {
1134
+ reasons.push(`unpatched files: ${unpatchedFiles.map((item) => item.relative).join(", ")}`);
1135
+ }
1136
+ return {
1137
+ name: "exposeContext",
1138
+ status: reasons.length ? "not-applied" : "applied",
1139
+ reason: reasons.length ? reasons.join("; ") : void 0,
1140
+ files
1141
+ };
1142
+ }
1143
+ function checkExtendLengthUnitsV3(rootDir, options) {
1144
+ const lengthUnitsFilePath = options.lengthUnitsFilePath ?? "lib/util/dataTypes.js";
1145
+ const variableName = options.variableName ?? "lengthUnits";
1146
+ const target = path4.resolve(rootDir, lengthUnitsFilePath);
1147
+ const files = fs4.existsSync(target) ? [path4.relative(rootDir, target)] : [];
1148
+ if (!fs4.existsSync(target)) {
1149
+ return {
1150
+ name: "extendLengthUnits",
1151
+ status: "not-applied",
1152
+ reason: `missing ${lengthUnitsFilePath}`,
1153
+ files
1154
+ };
1155
+ }
1156
+ const content = fs4.readFileSync(target, "utf8");
1157
+ const { found, missingUnits } = inspectLengthUnitsArray(content, variableName, options.units);
1158
+ if (!found) {
1159
+ return {
1160
+ name: "extendLengthUnits",
1161
+ status: "not-applied",
1162
+ reason: `could not locate ${variableName} array in ${lengthUnitsFilePath}`,
1163
+ files
1164
+ };
1165
+ }
1166
+ if (missingUnits.length) {
1167
+ return {
1168
+ name: "extendLengthUnits",
1169
+ status: "not-applied",
1170
+ reason: `missing units: ${missingUnits.join(", ")}`,
1171
+ files
1172
+ };
1173
+ }
1174
+ return {
1175
+ name: "extendLengthUnits",
1176
+ status: "applied",
1177
+ files
1178
+ };
1179
+ }
1180
+ function checkExtendLengthUnitsV4(rootDir, options) {
1181
+ const distDir = path4.resolve(rootDir, "dist");
1182
+ if (!fs4.existsSync(distDir)) {
1183
+ return {
1184
+ name: "extendLengthUnits",
1185
+ status: "not-applied",
1186
+ reason: "dist directory not found for Tailwind v4 package",
1187
+ files: []
1188
+ };
1189
+ }
1190
+ const result = applyExtendLengthUnitsPatchV4(rootDir, {
1191
+ ...options,
1192
+ enabled: true,
1193
+ overwrite: false
1194
+ });
1195
+ if (result.files.length === 0) {
1196
+ return {
1197
+ name: "extendLengthUnits",
1198
+ status: "not-applied",
1199
+ reason: "no bundle chunks matched the length unit pattern",
1200
+ files: []
1201
+ };
1202
+ }
1203
+ const files = result.files.map((file) => path4.relative(rootDir, file.file));
1204
+ const pending = result.files.filter((file) => !file.hasPatched);
1205
+ if (pending.length) {
1206
+ return {
1207
+ name: "extendLengthUnits",
1208
+ status: "not-applied",
1209
+ reason: `missing units in ${pending.length} bundle${pending.length > 1 ? "s" : ""}`,
1210
+ files: pending.map((file) => path4.relative(rootDir, file.file))
1211
+ };
1212
+ }
1213
+ return {
1214
+ name: "extendLengthUnits",
1215
+ status: "applied",
1216
+ files
1217
+ };
1218
+ }
1219
+ function checkExtendLengthUnitsPatch(context) {
1220
+ const { packageInfo, options, majorVersion } = context;
1221
+ if (!options.features.extendLengthUnits) {
1222
+ return {
1223
+ name: "extendLengthUnits",
1224
+ status: "skipped",
1225
+ reason: "extendLengthUnits feature disabled",
1226
+ files: []
1227
+ };
1228
+ }
1229
+ if (majorVersion === 2) {
1230
+ return {
1231
+ name: "extendLengthUnits",
1232
+ status: "unsupported",
1233
+ reason: "length unit extension is only applied for Tailwind v3/v4",
1234
+ files: []
1235
+ };
1236
+ }
1237
+ if (majorVersion === 3) {
1238
+ return checkExtendLengthUnitsV3(packageInfo.rootPath, options.features.extendLengthUnits);
1239
+ }
1240
+ return checkExtendLengthUnitsV4(packageInfo.rootPath, options.features.extendLengthUnits);
1241
+ }
1242
+ function getPatchStatusReport(context) {
1243
+ return {
1244
+ package: {
1245
+ name: context.packageInfo.name ?? context.packageInfo.packageJson?.name,
1246
+ version: context.packageInfo.version,
1247
+ root: context.packageInfo.rootPath
1248
+ },
1249
+ majorVersion: context.majorVersion,
1250
+ entries: [
1251
+ checkExposeContextPatch(context),
1252
+ checkExtendLengthUnitsPatch(context)
1253
+ ]
1254
+ };
1255
+ }
1256
+
1257
+ // src/runtime/class-collector.ts
1258
+ import process4 from "process";
1259
+ import fs5 from "fs-extra";
1260
+ import path5 from "pathe";
1261
+ function collectClassesFromContexts(contexts, filter) {
1262
+ const set = /* @__PURE__ */ new Set();
1263
+ for (const context of contexts) {
1264
+ if (!isObject(context) || !context.classCache) {
1265
+ continue;
1266
+ }
1267
+ for (const key of context.classCache.keys()) {
1268
+ const className = key.toString();
1269
+ if (filter(className)) {
1270
+ set.add(className);
1271
+ }
1272
+ }
1273
+ }
1274
+ return set;
1275
+ }
1276
+ async function collectClassesFromTailwindV4(options) {
1277
+ const set = /* @__PURE__ */ new Set();
1278
+ const v4Options = options.tailwind.v4;
1279
+ if (!v4Options) {
1280
+ return set;
1281
+ }
1282
+ const toAbsolute = (value) => {
1283
+ if (!value) {
1284
+ return void 0;
1285
+ }
1286
+ return path5.isAbsolute(value) ? value : path5.resolve(options.projectRoot, value);
1287
+ };
1288
+ const resolvedConfiguredBase = toAbsolute(v4Options.configuredBase);
1289
+ const resolvedDefaultBase = toAbsolute(v4Options.base) ?? process4.cwd();
1290
+ const resolveSources = (base) => {
1291
+ if (!v4Options.sources?.length) {
1292
+ return void 0;
1293
+ }
1294
+ return v4Options.sources.map((source) => ({
1295
+ base: source.base ?? base,
1296
+ pattern: source.pattern,
1297
+ negated: source.negated
1298
+ }));
1299
+ };
1300
+ if (v4Options.cssEntries.length > 0) {
1301
+ for (const entry of v4Options.cssEntries) {
1302
+ const filePath = path5.isAbsolute(entry) ? entry : path5.resolve(options.projectRoot, entry);
1303
+ if (!await fs5.pathExists(filePath)) {
1304
+ continue;
1305
+ }
1306
+ const css = await fs5.readFile(filePath, "utf8");
1307
+ const entryDir = path5.dirname(filePath);
1308
+ const baseForEntry = resolvedConfiguredBase ?? entryDir;
1309
+ const sources = resolveSources(baseForEntry);
1310
+ const candidates = await extractValidCandidates({
1311
+ cwd: options.projectRoot,
1312
+ base: baseForEntry,
1313
+ css,
1314
+ sources
1315
+ });
1316
+ for (const candidate of candidates) {
1317
+ if (options.filter(candidate)) {
1318
+ set.add(candidate);
1319
+ }
1320
+ }
1321
+ }
1322
+ } else {
1323
+ const baseForCss = resolvedConfiguredBase ?? resolvedDefaultBase;
1324
+ const sources = resolveSources(baseForCss);
1325
+ const candidates = await extractValidCandidates({
1326
+ cwd: options.projectRoot,
1327
+ base: baseForCss,
1328
+ css: v4Options.css,
1329
+ sources
1330
+ });
1331
+ for (const candidate of candidates) {
1332
+ if (options.filter(candidate)) {
1333
+ set.add(candidate);
1334
+ }
1335
+ }
1336
+ }
1337
+ return set;
1338
+ }
1339
+
1340
+ // src/runtime/context-registry.ts
1341
+ import { createRequire } from "module";
1342
+ import fs6 from "fs-extra";
1343
+ import path6 from "pathe";
1344
+ var require2 = createRequire(import.meta.url);
1345
+ function resolveRuntimeEntry(packageInfo, majorVersion) {
1346
+ const root = packageInfo.rootPath;
1347
+ if (majorVersion === 2) {
1348
+ const jitIndex = path6.join(root, "lib/jit/index.js");
1349
+ if (fs6.existsSync(jitIndex)) {
1350
+ return jitIndex;
1351
+ }
1352
+ } else if (majorVersion === 3) {
1353
+ const plugin = path6.join(root, "lib/plugin.js");
1354
+ const index = path6.join(root, "lib/index.js");
1355
+ if (fs6.existsSync(plugin)) {
1356
+ return plugin;
1357
+ }
1358
+ if (fs6.existsSync(index)) {
1359
+ return index;
1360
+ }
1361
+ }
1362
+ return void 0;
1363
+ }
1364
+ function loadRuntimeContexts(packageInfo, majorVersion, refProperty) {
1365
+ if (majorVersion === 4) {
1366
+ return [];
1367
+ }
1368
+ const entry = resolveRuntimeEntry(packageInfo, majorVersion);
1369
+ if (!entry) {
1370
+ return [];
1371
+ }
1372
+ const moduleExports = require2(entry);
1373
+ if (!moduleExports) {
1374
+ return [];
1375
+ }
1376
+ const ref = moduleExports[refProperty];
1377
+ if (!ref) {
1378
+ return [];
1379
+ }
1380
+ if (Array.isArray(ref)) {
1381
+ return ref;
1382
+ }
1383
+ if (typeof ref === "object" && Array.isArray(ref.value)) {
1384
+ return ref.value;
1385
+ }
1386
+ return [];
1387
+ }
1388
+
1389
+ // src/runtime/process-tailwindcss.ts
1390
+ import { createRequire as createRequire2 } from "module";
1391
+ import path7 from "pathe";
1392
+ import postcss from "postcss";
1393
+ import { loadConfig } from "tailwindcss-config";
1394
+ var require3 = createRequire2(import.meta.url);
1395
+ async function resolveConfigPath(options) {
1396
+ if (options.config && path7.isAbsolute(options.config)) {
1397
+ return options.config;
1398
+ }
1399
+ const result = await loadConfig({ cwd: options.cwd });
1400
+ if (!result) {
1401
+ throw new Error(`Unable to locate Tailwind CSS config from ${options.cwd}`);
1402
+ }
1403
+ return result.filepath;
1404
+ }
1405
+ async function runTailwindBuild(options) {
1406
+ const configPath = await resolveConfigPath(options);
1407
+ const pluginName = options.postcssPlugin ?? (options.majorVersion === 4 ? "@tailwindcss/postcss" : "tailwindcss");
1408
+ if (options.majorVersion === 4) {
1409
+ return postcss([
1410
+ require3(pluginName)({
1411
+ config: configPath
1412
+ })
1413
+ ]).process("@import 'tailwindcss';", {
1414
+ from: void 0
1415
+ });
1416
+ }
1417
+ return postcss([
1418
+ require3(pluginName)({
1419
+ config: configPath
1420
+ })
1421
+ ]).process("@tailwind base;@tailwind components;@tailwind utilities;", {
1422
+ from: void 0
1423
+ });
1424
+ }
1425
+
1426
+ // src/api/tailwindcss-patcher.ts
1427
+ import process5 from "process";
1428
+ import fs8 from "fs-extra";
1429
+ import { getPackageInfoSync } from "local-pkg";
1430
+ import path9 from "pathe";
1431
+ import { coerce } from "semver";
1432
+
1433
+ // src/options/legacy.ts
1434
+ function normalizeLegacyFeatures(patch) {
1435
+ const apply = patch?.applyPatches;
1436
+ const extend = apply?.extendLengthUnits;
1437
+ let extendOption = false;
1438
+ if (extend && typeof extend === "object") {
1439
+ extendOption = {
1440
+ ...extend,
1441
+ enabled: true
1442
+ };
1443
+ } else if (extend === true) {
1444
+ extendOption = {
1445
+ enabled: true,
1446
+ units: ["rpx"],
1447
+ overwrite: patch?.overwrite
1448
+ };
1449
+ }
1450
+ return {
1451
+ exposeContext: apply?.exportContext ?? true,
1452
+ extendLengthUnits: extendOption
1453
+ };
1454
+ }
1455
+ function fromLegacyOptions(options) {
1456
+ if (!options) {
1457
+ return {};
1458
+ }
1459
+ const patch = options.patch;
1460
+ const features = normalizeLegacyFeatures(patch);
1461
+ const output = patch?.output;
1462
+ const tailwindConfig = patch?.tailwindcss;
1463
+ const tailwindVersion = tailwindConfig?.version;
1464
+ const tailwindV2 = tailwindConfig?.v2;
1465
+ const tailwindV3 = tailwindConfig?.v3;
1466
+ const tailwindV4 = tailwindConfig?.v4;
1467
+ const tailwindConfigPath = tailwindV3?.config ?? tailwindV2?.config;
1468
+ const tailwindCwd = tailwindV3?.cwd ?? tailwindV2?.cwd ?? patch?.cwd;
1469
+ return {
1470
+ cwd: patch?.cwd,
1471
+ overwrite: patch?.overwrite,
1472
+ filter: patch?.filter,
1473
+ cache: typeof options.cache === "boolean" ? options.cache : options.cache ? {
1474
+ ...options.cache,
1475
+ enabled: options.cache.enabled ?? true
1476
+ } : void 0,
1477
+ output: output ? {
1478
+ file: output.filename,
1479
+ pretty: output.loose ? 2 : false,
1480
+ removeUniversalSelector: output.removeUniversalSelector
1481
+ } : void 0,
1482
+ tailwind: {
1483
+ packageName: patch?.packageName,
1484
+ version: tailwindVersion,
1485
+ resolve: patch?.resolve,
1486
+ config: tailwindConfigPath,
1487
+ cwd: tailwindCwd,
1488
+ v2: tailwindV2,
1489
+ v3: tailwindV3,
1490
+ v4: tailwindV4
1491
+ },
1492
+ features: {
1493
+ exposeContext: features.exposeContext,
1494
+ extendLengthUnits: features.extendLengthUnits
1495
+ }
1496
+ };
1497
+ }
1498
+ function fromUnifiedConfig(registry) {
1499
+ if (!registry) {
1500
+ return {};
1501
+ }
1502
+ const tailwind = registry.tailwind;
1503
+ const output = registry.output;
1504
+ const pretty = (() => {
1505
+ if (output?.pretty === void 0) {
1506
+ return void 0;
1507
+ }
1508
+ if (typeof output.pretty === "boolean") {
1509
+ return output.pretty ? 2 : false;
1510
+ }
1511
+ return output.pretty;
1512
+ })();
1165
1513
  return {
1166
- code: hasPatched ? content : generate(ast).code,
1167
- hasPatched
1514
+ output: output ? {
1515
+ file: output.file,
1516
+ pretty,
1517
+ removeUniversalSelector: output.stripUniversalSelector
1518
+ } : void 0,
1519
+ tailwind: tailwind ? {
1520
+ version: tailwind.version,
1521
+ packageName: tailwind.package,
1522
+ resolve: tailwind.resolve,
1523
+ config: tailwind.config,
1524
+ cwd: tailwind.cwd,
1525
+ v2: tailwind.legacy,
1526
+ v3: tailwind.classic,
1527
+ v4: tailwind.next
1528
+ } : void 0
1168
1529
  };
1169
1530
  }
1170
1531
 
1171
1532
  // src/patching/operations/export-context/index.ts
1533
+ import fs7 from "fs-extra";
1534
+ import path8 from "pathe";
1172
1535
  function writeFileIfRequired(filePath, code, overwrite, successMessage) {
1173
1536
  if (!overwrite) {
1174
1537
  return;
1175
1538
  }
1176
- fs5.writeFileSync(filePath, code, {
1539
+ fs7.writeFileSync(filePath, code, {
1177
1540
  encoding: "utf8"
1178
1541
  });
1179
1542
  logger_default.success(successMessage);
@@ -1186,9 +1549,9 @@ function applyExposeContextPatch(params) {
1186
1549
  };
1187
1550
  if (majorVersion === 3) {
1188
1551
  const processFileRelative = "lib/processTailwindFeatures.js";
1189
- const processFilePath = path6.resolve(rootDir, processFileRelative);
1190
- if (fs5.existsSync(processFilePath)) {
1191
- const content = fs5.readFileSync(processFilePath, "utf8");
1552
+ const processFilePath = path8.resolve(rootDir, processFileRelative);
1553
+ if (fs7.existsSync(processFilePath)) {
1554
+ const content = fs7.readFileSync(processFilePath, "utf8");
1192
1555
  const { code, hasPatched } = transformProcessTailwindFeaturesReturnContext(content);
1193
1556
  result.files[processFileRelative] = code;
1194
1557
  if (!hasPatched) {
@@ -1202,10 +1565,10 @@ function applyExposeContextPatch(params) {
1202
1565
  }
1203
1566
  }
1204
1567
  const pluginCandidates = ["lib/plugin.js", "lib/index.js"];
1205
- const pluginRelative = pluginCandidates.find((candidate) => fs5.existsSync(path6.resolve(rootDir, candidate)));
1568
+ const pluginRelative = pluginCandidates.find((candidate) => fs7.existsSync(path8.resolve(rootDir, candidate)));
1206
1569
  if (pluginRelative) {
1207
- const pluginPath = path6.resolve(rootDir, pluginRelative);
1208
- const content = fs5.readFileSync(pluginPath, "utf8");
1570
+ const pluginPath = path8.resolve(rootDir, pluginRelative);
1571
+ const content = fs7.readFileSync(pluginPath, "utf8");
1209
1572
  const { code, hasPatched } = transformPostcssPlugin(content, { refProperty });
1210
1573
  result.files[pluginRelative] = code;
1211
1574
  if (!hasPatched) {
@@ -1220,9 +1583,9 @@ function applyExposeContextPatch(params) {
1220
1583
  }
1221
1584
  } else if (majorVersion === 2) {
1222
1585
  const processFileRelative = "lib/jit/processTailwindFeatures.js";
1223
- const processFilePath = path6.resolve(rootDir, processFileRelative);
1224
- if (fs5.existsSync(processFilePath)) {
1225
- const content = fs5.readFileSync(processFilePath, "utf8");
1586
+ const processFilePath = path8.resolve(rootDir, processFileRelative);
1587
+ if (fs7.existsSync(processFilePath)) {
1588
+ const content = fs7.readFileSync(processFilePath, "utf8");
1226
1589
  const { code, hasPatched } = transformProcessTailwindFeaturesReturnContextV2(content);
1227
1590
  result.files[processFileRelative] = code;
1228
1591
  if (!hasPatched) {
@@ -1236,9 +1599,9 @@ function applyExposeContextPatch(params) {
1236
1599
  }
1237
1600
  }
1238
1601
  const pluginRelative = "lib/jit/index.js";
1239
- const pluginPath = path6.resolve(rootDir, pluginRelative);
1240
- if (fs5.existsSync(pluginPath)) {
1241
- const content = fs5.readFileSync(pluginPath, "utf8");
1602
+ const pluginPath = path8.resolve(rootDir, pluginRelative);
1603
+ if (fs7.existsSync(pluginPath)) {
1604
+ const content = fs7.readFileSync(pluginPath, "utf8");
1242
1605
  const { code, hasPatched } = transformPostcssPluginV2(content, { refProperty });
1243
1606
  result.files[pluginRelative] = code;
1244
1607
  if (!hasPatched) {
@@ -1255,147 +1618,6 @@ function applyExposeContextPatch(params) {
1255
1618
  return result;
1256
1619
  }
1257
1620
 
1258
- // src/patching/operations/extend-length-units.ts
1259
- import * as t3 from "@babel/types";
1260
- import fs6 from "fs-extra";
1261
- import path7 from "pathe";
1262
- function updateLengthUnitsArray(content, options) {
1263
- const { variableName = "lengthUnits", units } = options;
1264
- const ast = parse(content);
1265
- let arrayRef;
1266
- let changed = false;
1267
- traverse(ast, {
1268
- Identifier(path10) {
1269
- if (path10.node.name === variableName && t3.isVariableDeclarator(path10.parent) && t3.isArrayExpression(path10.parent.init)) {
1270
- arrayRef = path10.parent.init;
1271
- const existing = new Set(
1272
- path10.parent.init.elements.map((element) => t3.isStringLiteral(element) ? element.value : void 0).filter(Boolean)
1273
- );
1274
- for (const unit of units) {
1275
- if (!existing.has(unit)) {
1276
- path10.parent.init.elements = path10.parent.init.elements.map((element) => {
1277
- if (t3.isStringLiteral(element)) {
1278
- return t3.stringLiteral(element.value);
1279
- }
1280
- return element;
1281
- });
1282
- path10.parent.init.elements.push(t3.stringLiteral(unit));
1283
- changed = true;
1284
- }
1285
- }
1286
- }
1287
- }
1288
- });
1289
- return {
1290
- arrayRef,
1291
- changed
1292
- };
1293
- }
1294
- function applyExtendLengthUnitsPatchV3(rootDir, options) {
1295
- if (!options.enabled) {
1296
- return { changed: false, code: void 0 };
1297
- }
1298
- const opts = {
1299
- ...options,
1300
- lengthUnitsFilePath: options.lengthUnitsFilePath ?? "lib/util/dataTypes.js",
1301
- variableName: options.variableName ?? "lengthUnits"
1302
- };
1303
- const dataTypesFilePath = path7.resolve(rootDir, opts.lengthUnitsFilePath);
1304
- const exists = fs6.existsSync(dataTypesFilePath);
1305
- if (!exists) {
1306
- return { changed: false, code: void 0 };
1307
- }
1308
- const content = fs6.readFileSync(dataTypesFilePath, "utf8");
1309
- const { arrayRef, changed } = updateLengthUnitsArray(content, opts);
1310
- if (!arrayRef || !changed) {
1311
- return { changed: false, code: void 0 };
1312
- }
1313
- const { code } = generate(arrayRef, {
1314
- jsescOption: { quotes: "single" }
1315
- });
1316
- if (arrayRef.start != null && arrayRef.end != null) {
1317
- const nextCode = `${content.slice(0, arrayRef.start)}${code}${content.slice(arrayRef.end)}`;
1318
- if (opts.overwrite) {
1319
- const target = opts.destPath ? path7.resolve(opts.destPath) : dataTypesFilePath;
1320
- fs6.writeFileSync(target, nextCode, "utf8");
1321
- logger_default.success("Patched Tailwind CSS length unit list (v3).");
1322
- }
1323
- return {
1324
- changed: true,
1325
- code: nextCode
1326
- };
1327
- }
1328
- return {
1329
- changed: false,
1330
- code: void 0
1331
- };
1332
- }
1333
- function applyExtendLengthUnitsPatchV4(rootDir, options) {
1334
- if (!options.enabled) {
1335
- return { files: [], changed: false };
1336
- }
1337
- const opts = { ...options };
1338
- const distDir = path7.resolve(rootDir, "dist");
1339
- if (!fs6.existsSync(distDir)) {
1340
- return { files: [], changed: false };
1341
- }
1342
- const entries = fs6.readdirSync(distDir);
1343
- const chunkNames = entries.filter((entry) => entry.endsWith(".js") || entry.endsWith(".mjs"));
1344
- const pattern = /\[\s*["']cm["'],\s*["']mm["'],[\w,"']+\]/;
1345
- const candidates = chunkNames.map((chunkName) => {
1346
- const file = path7.join(distDir, chunkName);
1347
- const code = fs6.readFileSync(file, "utf8");
1348
- const match = pattern.exec(code);
1349
- if (!match) {
1350
- return null;
1351
- }
1352
- return {
1353
- file,
1354
- code,
1355
- match,
1356
- hasPatched: false
1357
- };
1358
- }).filter((candidate) => candidate !== null);
1359
- for (const item of candidates) {
1360
- const { code, file, match } = item;
1361
- const ast = parse(match[0], { sourceType: "unambiguous" });
1362
- traverse(ast, {
1363
- ArrayExpression(path10) {
1364
- for (const unit of opts.units) {
1365
- if (path10.node.elements.some((element) => t3.isStringLiteral(element) && element.value === unit)) {
1366
- item.hasPatched = true;
1367
- return;
1368
- }
1369
- path10.node.elements.push(t3.stringLiteral(unit));
1370
- }
1371
- }
1372
- });
1373
- if (item.hasPatched) {
1374
- continue;
1375
- }
1376
- const { code: replacement } = generate(ast, { minified: true });
1377
- const start = match.index ?? 0;
1378
- const end = start + match[0].length;
1379
- item.code = spliceChangesIntoString(code, [
1380
- {
1381
- start,
1382
- end,
1383
- replacement: replacement.endsWith(";") ? replacement.slice(0, -1) : replacement
1384
- }
1385
- ]);
1386
- if (opts.overwrite) {
1387
- fs6.writeFileSync(file, item.code, "utf8");
1388
- }
1389
- }
1390
- if (candidates.some((file) => !file.hasPatched)) {
1391
- logger_default.success("Patched Tailwind CSS length unit list (v4).");
1392
- }
1393
- return {
1394
- changed: candidates.some((file) => !file.hasPatched),
1395
- files: candidates
1396
- };
1397
- }
1398
-
1399
1621
  // src/patching/patch-runner.ts
1400
1622
  function applyTailwindPatches(context) {
1401
1623
  const { packageInfo, options, majorVersion } = context;
@@ -1494,6 +1716,13 @@ var TailwindcssPatcher = class {
1494
1716
  majorVersion: this.majorVersion
1495
1717
  });
1496
1718
  }
1719
+ async getPatchStatus() {
1720
+ return getPatchStatusReport({
1721
+ packageInfo: this.packageInfo,
1722
+ options: this.options,
1723
+ majorVersion: this.majorVersion
1724
+ });
1725
+ }
1497
1726
  getContexts() {
1498
1727
  return loadRuntimeContexts(
1499
1728
  this.packageInfo,
@@ -1585,13 +1814,13 @@ var TailwindcssPatcher = class {
1585
1814
  if (!shouldWrite || !this.options.output.file) {
1586
1815
  return result;
1587
1816
  }
1588
- const target = path8.resolve(this.options.output.file);
1589
- await fs7.ensureDir(path8.dirname(target));
1817
+ const target = path9.resolve(this.options.output.file);
1818
+ await fs8.ensureDir(path9.dirname(target));
1590
1819
  if (this.options.output.format === "json") {
1591
1820
  const spaces = typeof this.options.output.pretty === "number" ? this.options.output.pretty : void 0;
1592
- await fs7.writeJSON(target, classList, { spaces });
1821
+ await fs8.writeJSON(target, classList, { spaces });
1593
1822
  } else {
1594
- await fs7.writeFile(target, `${classList.join("\n")}
1823
+ await fs8.writeFile(target, `${classList.join("\n")}
1595
1824
  `, "utf8");
1596
1825
  }
1597
1826
  logger_default.success(`Tailwind CSS class list saved to ${target.replace(process5.cwd(), ".")}`);
@@ -1716,9 +1945,9 @@ var acceptChars = [..."abcdefghijklmnopqrstuvwxyz"];
1716
1945
 
1717
1946
  // src/cli/commands.ts
1718
1947
  import cac from "cac";
1719
- import fs8 from "fs-extra";
1720
- import path9 from "pathe";
1721
- var tailwindcssPatchCommands = ["install", "extract", "tokens", "init"];
1948
+ import fs9 from "fs-extra";
1949
+ import path10 from "pathe";
1950
+ var tailwindcssPatchCommands = ["install", "extract", "tokens", "init", "status"];
1722
1951
  var TOKEN_FORMATS = ["json", "lines", "grouped-json"];
1723
1952
  var DEFAULT_TOKEN_REPORT = ".tw-patch/tw-token-report.json";
1724
1953
  function formatTokenLine(entry) {
@@ -1744,7 +1973,7 @@ function resolveCwd(rawCwd) {
1744
1973
  if (!rawCwd) {
1745
1974
  return process6.cwd();
1746
1975
  }
1747
- return path9.resolve(rawCwd);
1976
+ return path10.resolve(rawCwd);
1748
1977
  }
1749
1978
  function createDefaultRunner(factory) {
1750
1979
  let promise;
@@ -1846,6 +2075,13 @@ function buildDefaultCommandDefinitions() {
1846
2075
  init: {
1847
2076
  description: "Generate a tailwindcss-patch config file",
1848
2077
  optionDefs: [createCwdOptionDefinition()]
2078
+ },
2079
+ status: {
2080
+ description: "Check which Tailwind patches are applied",
2081
+ optionDefs: [
2082
+ createCwdOptionDefinition(),
2083
+ { flags: "--json", description: "Print a JSON report of patch status" }
2084
+ ]
1849
2085
  }
1850
2086
  };
1851
2087
  }
@@ -1949,15 +2185,15 @@ async function tokensCommandDefaultHandler(ctx) {
1949
2185
  const grouped = format === "grouped-json" ? buildGrouped() : null;
1950
2186
  const resolveGrouped = () => grouped ?? buildGrouped();
1951
2187
  if (shouldWrite) {
1952
- const target = path9.resolve(targetFile);
1953
- await fs8.ensureDir(path9.dirname(target));
2188
+ const target = path10.resolve(targetFile);
2189
+ await fs9.ensureDir(path10.dirname(target));
1954
2190
  if (format === "json") {
1955
- await fs8.writeJSON(target, report, { spaces: 2 });
2191
+ await fs9.writeJSON(target, report, { spaces: 2 });
1956
2192
  } else if (format === "grouped-json") {
1957
- await fs8.writeJSON(target, resolveGrouped(), { spaces: 2 });
2193
+ await fs9.writeJSON(target, resolveGrouped(), { spaces: 2 });
1958
2194
  } else {
1959
2195
  const lines = report.entries.map(formatTokenLine);
1960
- await fs8.writeFile(target, `${lines.join("\n")}
2196
+ await fs9.writeFile(target, `${lines.join("\n")}
1961
2197
  `, "utf8");
1962
2198
  }
1963
2199
  logger_default.success(`Collected ${report.entries.length} tokens (${format}) \u2192 ${target.replace(process6.cwd(), ".")}`);
@@ -2002,6 +2238,46 @@ async function initCommandDefaultHandler(ctx) {
2002
2238
  await initConfig(ctx.cwd);
2003
2239
  logger_default.success(`\u2728 ${CONFIG_NAME}.config.ts initialized!`);
2004
2240
  }
2241
+ function formatFilesHint(entry) {
2242
+ if (!entry.files.length) {
2243
+ return "";
2244
+ }
2245
+ return ` (${entry.files.join(", ")})`;
2246
+ }
2247
+ async function statusCommandDefaultHandler(ctx) {
2248
+ const patcher = await ctx.createPatcher();
2249
+ const report = await patcher.getPatchStatus();
2250
+ if (ctx.args.json) {
2251
+ logger_default.log(JSON.stringify(report, null, 2));
2252
+ return report;
2253
+ }
2254
+ const applied = report.entries.filter((entry) => entry.status === "applied");
2255
+ const pending = report.entries.filter((entry) => entry.status === "not-applied");
2256
+ const skipped = report.entries.filter((entry) => entry.status === "skipped" || entry.status === "unsupported");
2257
+ const packageLabel = `${report.package.name ?? "tailwindcss"}@${report.package.version ?? "unknown"}`;
2258
+ logger_default.info(`Patch status for ${packageLabel} (v${report.majorVersion})`);
2259
+ if (applied.length) {
2260
+ logger_default.success("Applied:");
2261
+ applied.forEach((entry) => logger_default.success(` \u2022 ${entry.name}${formatFilesHint(entry)}`));
2262
+ }
2263
+ if (pending.length) {
2264
+ logger_default.warn("Needs attention:");
2265
+ pending.forEach((entry) => {
2266
+ const details = entry.reason ? ` \u2013 ${entry.reason}` : "";
2267
+ logger_default.warn(` \u2022 ${entry.name}${formatFilesHint(entry)}${details}`);
2268
+ });
2269
+ } else {
2270
+ logger_default.success("All applicable patches are applied.");
2271
+ }
2272
+ if (skipped.length) {
2273
+ logger_default.info("Skipped:");
2274
+ skipped.forEach((entry) => {
2275
+ const details = entry.reason ? ` \u2013 ${entry.reason}` : "";
2276
+ logger_default.info(` \u2022 ${entry.name}${details}`);
2277
+ });
2278
+ }
2279
+ return report;
2280
+ }
2005
2281
  function mountTailwindcssPatchCommands(cli, options = {}) {
2006
2282
  const prefix = options.commandPrefix ?? "";
2007
2283
  const selectedCommands = options.commands ?? tailwindcssPatchCommands;
@@ -2070,6 +2346,22 @@ function mountTailwindcssPatchCommands(cli, options = {}) {
2070
2346
  );
2071
2347
  });
2072
2348
  metadata.aliases.forEach((alias) => command.alias(alias));
2349
+ },
2350
+ status: () => {
2351
+ const metadata = resolveCommandMetadata("status", options, prefix, defaultDefinitions);
2352
+ const command = cli.command(metadata.name, metadata.description);
2353
+ applyCommandOptions(command, metadata.optionDefs);
2354
+ command.action(async (args) => {
2355
+ return runWithCommandHandler(
2356
+ cli,
2357
+ command,
2358
+ "status",
2359
+ args,
2360
+ options.commandHandlers?.status,
2361
+ statusCommandDefaultHandler
2362
+ );
2363
+ });
2364
+ metadata.aliases.forEach((alias) => command.alias(alias));
2073
2365
  }
2074
2366
  };
2075
2367
  for (const name of selectedCommands) {
@@ -2095,6 +2387,7 @@ export {
2095
2387
  extractProjectCandidatesWithPositions,
2096
2388
  groupTokensByFile,
2097
2389
  normalizeOptions,
2390
+ getPatchStatusReport,
2098
2391
  collectClassesFromContexts,
2099
2392
  collectClassesFromTailwindV4,
2100
2393
  loadRuntimeContexts,