tailwindcss-patch 8.4.3 → 8.5.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.
@@ -520,372 +520,69 @@ function normalizeOptions(options = {}) {
520
520
  };
521
521
  }
522
522
 
523
- // src/runtime/class-collector.ts
524
- import process4 from "process";
525
- import fs3 from "fs-extra";
526
- import path3 from "pathe";
523
+ // src/patching/status.ts
524
+ import * as t4 from "@babel/types";
525
+ import fs4 from "fs-extra";
526
+ import path4 from "pathe";
527
527
 
528
- // src/utils.ts
529
- function isObject(val) {
530
- return val !== null && typeof val === "object" && Array.isArray(val) === false;
528
+ // src/babel/index.ts
529
+ import _babelGenerate from "@babel/generator";
530
+ import _babelTraverse from "@babel/traverse";
531
+ import { parse, parseExpression } from "@babel/parser";
532
+ function _interopDefaultCompat(e) {
533
+ return e && typeof e === "object" && "default" in e ? e.default : e;
531
534
  }
532
- function spliceChangesIntoString(str, changes) {
533
- if (!changes[0]) {
534
- return str;
535
+ var generate = _interopDefaultCompat(_babelGenerate);
536
+ var traverse = _interopDefaultCompat(_babelTraverse);
537
+
538
+ // src/patching/operations/export-context/postcss-v2.ts
539
+ import * as t from "@babel/types";
540
+ var IDENTIFIER_RE = /^[A-Z_$][\w$]*$/i;
541
+ function toIdentifierName(property) {
542
+ if (!property) {
543
+ return "contextRef";
535
544
  }
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;
545
+ const sanitized = property.replace(/[^\w$]/gu, "_");
546
+ if (/^\d/.test(sanitized)) {
547
+ return `_${sanitized}`;
548
548
  }
549
- result += str.slice(previous.end);
550
- return result;
549
+ return sanitized || "contextRef";
551
550
  }
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
- }
551
+ function createExportsMember(property) {
552
+ if (IDENTIFIER_RE.test(property)) {
553
+ return t.memberExpression(t.identifier("exports"), t.identifier(property));
566
554
  }
567
- return set;
555
+ return t.memberExpression(t.identifier("exports"), t.stringLiteral(property), true);
568
556
  }
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;
557
+ function transformProcessTailwindFeaturesReturnContextV2(content) {
558
+ const ast = parse(content, {
559
+ sourceType: "unambiguous"
560
+ });
561
+ let hasPatched = false;
562
+ traverse(ast, {
563
+ FunctionDeclaration(path11) {
564
+ const node = path11.node;
565
+ if (node.id?.name !== "processTailwindFeatures" || node.body.body.length !== 1 || !t.isReturnStatement(node.body.body[0])) {
566
+ return;
598
567
  }
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
- }
568
+ const returnStatement3 = node.body.body[0];
569
+ if (!t.isFunctionExpression(returnStatement3.argument)) {
570
+ return;
613
571
  }
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);
572
+ const body = returnStatement3.argument.body.body;
573
+ const lastStatement = body[body.length - 1];
574
+ const alreadyReturnsContext = Boolean(
575
+ t.isReturnStatement(lastStatement) && t.isIdentifier(lastStatement.argument) && lastStatement.argument.name === "context"
576
+ );
577
+ hasPatched = alreadyReturnsContext;
578
+ if (!alreadyReturnsContext) {
579
+ body.push(t.returnStatement(t.identifier("context")));
627
580
  }
628
581
  }
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
582
  });
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
583
  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
584
+ code: hasPatched ? content : generate(ast).code,
585
+ hasPatched
889
586
  };
890
587
  }
891
588
  function transformPostcssPluginV2(content, options) {
@@ -895,8 +592,8 @@ function transformPostcssPluginV2(content, options) {
895
592
  const ast = parse(content);
896
593
  let hasPatched = false;
897
594
  traverse(ast, {
898
- Program(path10) {
899
- const program = path10.node;
595
+ Program(path11) {
596
+ const program = path11.node;
900
597
  const index = program.body.findIndex((statement) => {
901
598
  return t.isFunctionDeclaration(statement) && statement.id?.name === "_default";
902
599
  });
@@ -930,11 +627,11 @@ function transformPostcssPluginV2(content, options) {
930
627
  );
931
628
  }
932
629
  },
933
- FunctionDeclaration(path10) {
630
+ FunctionDeclaration(path11) {
934
631
  if (hasPatched) {
935
632
  return;
936
633
  }
937
- const fn = path10.node;
634
+ const fn = path11.node;
938
635
  if (fn.id?.name !== "_default") {
939
636
  return;
940
637
  }
@@ -1023,8 +720,8 @@ function transformProcessTailwindFeaturesReturnContext(content) {
1023
720
  const ast = parse(content);
1024
721
  let hasPatched = false;
1025
722
  traverse(ast, {
1026
- FunctionDeclaration(path10) {
1027
- const node = path10.node;
723
+ FunctionDeclaration(path11) {
724
+ const node = path11.node;
1028
725
  if (node.id?.name !== "processTailwindFeatures" || node.body.body.length !== 1) {
1029
726
  return;
1030
727
  }
@@ -1056,8 +753,8 @@ function transformPostcssPlugin(content, { refProperty }) {
1056
753
  const valueMember = t2.memberExpression(refIdentifier, t2.identifier("value"));
1057
754
  let hasPatched = false;
1058
755
  traverse(ast, {
1059
- Program(path10) {
1060
- const program = path10.node;
756
+ Program(path11) {
757
+ const program = path11.node;
1061
758
  const index = program.body.findIndex((statement) => {
1062
759
  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
760
  });
@@ -1095,11 +792,11 @@ function transformPostcssPlugin(content, { refProperty }) {
1095
792
  );
1096
793
  }
1097
794
  },
1098
- FunctionExpression(path10) {
795
+ FunctionExpression(path11) {
1099
796
  if (hasPatched) {
1100
797
  return;
1101
798
  }
1102
- const fn = path10.node;
799
+ const fn = path11.node;
1103
800
  if (fn.id?.name !== "tailwindcss" || fn.body.body.length !== 1) {
1104
801
  return;
1105
802
  }
@@ -1161,19 +858,664 @@ function transformPostcssPlugin(content, { refProperty }) {
1161
858
  )
1162
859
  );
1163
860
  }
1164
- });
861
+ });
862
+ return {
863
+ code: hasPatched ? content : generate(ast).code,
864
+ hasPatched
865
+ };
866
+ }
867
+
868
+ // src/patching/operations/extend-length-units.ts
869
+ import * as t3 from "@babel/types";
870
+ import fs3 from "fs-extra";
871
+ import path3 from "pathe";
872
+
873
+ // src/utils.ts
874
+ function isObject(val) {
875
+ return val !== null && typeof val === "object" && Array.isArray(val) === false;
876
+ }
877
+ function spliceChangesIntoString(str, changes) {
878
+ if (!changes[0]) {
879
+ return str;
880
+ }
881
+ changes.sort((a, b) => {
882
+ return a.end - b.end || a.start - b.start;
883
+ });
884
+ let result = "";
885
+ let previous = changes[0];
886
+ result += str.slice(0, previous.start);
887
+ result += previous.replacement;
888
+ for (let i = 1; i < changes.length; ++i) {
889
+ const change = changes[i];
890
+ result += str.slice(previous.end, change.start);
891
+ result += change.replacement;
892
+ previous = change;
893
+ }
894
+ result += str.slice(previous.end);
895
+ return result;
896
+ }
897
+
898
+ // src/patching/operations/extend-length-units.ts
899
+ function updateLengthUnitsArray(content, options) {
900
+ const { variableName = "lengthUnits", units } = options;
901
+ const ast = parse(content);
902
+ let arrayRef;
903
+ let changed = false;
904
+ traverse(ast, {
905
+ Identifier(path11) {
906
+ if (path11.node.name === variableName && t3.isVariableDeclarator(path11.parent) && t3.isArrayExpression(path11.parent.init)) {
907
+ arrayRef = path11.parent.init;
908
+ const existing = new Set(
909
+ path11.parent.init.elements.map((element) => t3.isStringLiteral(element) ? element.value : void 0).filter(Boolean)
910
+ );
911
+ for (const unit of units) {
912
+ if (!existing.has(unit)) {
913
+ path11.parent.init.elements = path11.parent.init.elements.map((element) => {
914
+ if (t3.isStringLiteral(element)) {
915
+ return t3.stringLiteral(element.value);
916
+ }
917
+ return element;
918
+ });
919
+ path11.parent.init.elements.push(t3.stringLiteral(unit));
920
+ changed = true;
921
+ }
922
+ }
923
+ }
924
+ }
925
+ });
926
+ return {
927
+ arrayRef,
928
+ changed
929
+ };
930
+ }
931
+ function applyExtendLengthUnitsPatchV3(rootDir, options) {
932
+ if (!options.enabled) {
933
+ return { changed: false, code: void 0 };
934
+ }
935
+ const opts = {
936
+ ...options,
937
+ lengthUnitsFilePath: options.lengthUnitsFilePath ?? "lib/util/dataTypes.js",
938
+ variableName: options.variableName ?? "lengthUnits"
939
+ };
940
+ const dataTypesFilePath = path3.resolve(rootDir, opts.lengthUnitsFilePath);
941
+ const exists = fs3.existsSync(dataTypesFilePath);
942
+ if (!exists) {
943
+ return { changed: false, code: void 0 };
944
+ }
945
+ const content = fs3.readFileSync(dataTypesFilePath, "utf8");
946
+ const { arrayRef, changed } = updateLengthUnitsArray(content, opts);
947
+ if (!arrayRef || !changed) {
948
+ return { changed: false, code: void 0 };
949
+ }
950
+ const { code } = generate(arrayRef, {
951
+ jsescOption: { quotes: "single" }
952
+ });
953
+ if (arrayRef.start != null && arrayRef.end != null) {
954
+ const nextCode = `${content.slice(0, arrayRef.start)}${code}${content.slice(arrayRef.end)}`;
955
+ if (opts.overwrite) {
956
+ const target = opts.destPath ? path3.resolve(opts.destPath) : dataTypesFilePath;
957
+ fs3.writeFileSync(target, nextCode, "utf8");
958
+ logger_default.success("Patched Tailwind CSS length unit list (v3).");
959
+ }
960
+ return {
961
+ changed: true,
962
+ code: nextCode
963
+ };
964
+ }
965
+ return {
966
+ changed: false,
967
+ code: void 0
968
+ };
969
+ }
970
+ function applyExtendLengthUnitsPatchV4(rootDir, options) {
971
+ if (!options.enabled) {
972
+ return { files: [], changed: false };
973
+ }
974
+ const opts = { ...options };
975
+ const distDir = path3.resolve(rootDir, "dist");
976
+ if (!fs3.existsSync(distDir)) {
977
+ return { files: [], changed: false };
978
+ }
979
+ const entries = fs3.readdirSync(distDir);
980
+ const chunkNames = entries.filter((entry) => entry.endsWith(".js") || entry.endsWith(".mjs"));
981
+ const pattern = /\[\s*["']cm["'],\s*["']mm["'],[\w,"']+\]/;
982
+ const candidates = chunkNames.map((chunkName) => {
983
+ const file = path3.join(distDir, chunkName);
984
+ const code = fs3.readFileSync(file, "utf8");
985
+ const match = pattern.exec(code);
986
+ if (!match) {
987
+ return null;
988
+ }
989
+ return {
990
+ file,
991
+ code,
992
+ match,
993
+ hasPatched: false
994
+ };
995
+ }).filter((candidate) => candidate !== null);
996
+ for (const item of candidates) {
997
+ const { code, file, match } = item;
998
+ const ast = parse(match[0], { sourceType: "unambiguous" });
999
+ traverse(ast, {
1000
+ ArrayExpression(path11) {
1001
+ for (const unit of opts.units) {
1002
+ if (path11.node.elements.some((element) => t3.isStringLiteral(element) && element.value === unit)) {
1003
+ item.hasPatched = true;
1004
+ return;
1005
+ }
1006
+ path11.node.elements.push(t3.stringLiteral(unit));
1007
+ }
1008
+ }
1009
+ });
1010
+ if (item.hasPatched) {
1011
+ continue;
1012
+ }
1013
+ const { code: replacement } = generate(ast, { minified: true });
1014
+ const start = match.index ?? 0;
1015
+ const end = start + match[0].length;
1016
+ item.code = spliceChangesIntoString(code, [
1017
+ {
1018
+ start,
1019
+ end,
1020
+ replacement: replacement.endsWith(";") ? replacement.slice(0, -1) : replacement
1021
+ }
1022
+ ]);
1023
+ if (opts.overwrite) {
1024
+ fs3.writeFileSync(file, item.code, "utf8");
1025
+ }
1026
+ }
1027
+ if (candidates.some((file) => !file.hasPatched)) {
1028
+ logger_default.success("Patched Tailwind CSS length unit list (v4).");
1029
+ }
1030
+ return {
1031
+ changed: candidates.some((file) => !file.hasPatched),
1032
+ files: candidates
1033
+ };
1034
+ }
1035
+
1036
+ // src/patching/status.ts
1037
+ function inspectLengthUnitsArray(content, variableName, units) {
1038
+ const ast = parse(content);
1039
+ let found = false;
1040
+ let missingUnits = [];
1041
+ traverse(ast, {
1042
+ Identifier(path11) {
1043
+ if (path11.node.name === variableName && t4.isVariableDeclarator(path11.parent) && t4.isArrayExpression(path11.parent.init)) {
1044
+ found = true;
1045
+ const existing = new Set(
1046
+ path11.parent.init.elements.map((element) => t4.isStringLiteral(element) ? element.value : void 0).filter(Boolean)
1047
+ );
1048
+ missingUnits = units.filter((unit) => !existing.has(unit));
1049
+ path11.stop();
1050
+ }
1051
+ }
1052
+ });
1053
+ return {
1054
+ found,
1055
+ missingUnits
1056
+ };
1057
+ }
1058
+ function checkExposeContextPatch(context) {
1059
+ const { packageInfo, options, majorVersion } = context;
1060
+ const refProperty = options.features.exposeContext.refProperty;
1061
+ if (!options.features.exposeContext.enabled) {
1062
+ return {
1063
+ name: "exposeContext",
1064
+ status: "skipped",
1065
+ reason: "exposeContext feature disabled",
1066
+ files: []
1067
+ };
1068
+ }
1069
+ if (majorVersion === 4) {
1070
+ return {
1071
+ name: "exposeContext",
1072
+ status: "unsupported",
1073
+ reason: "Context export patch is only required for Tailwind v2/v3",
1074
+ files: []
1075
+ };
1076
+ }
1077
+ const checks = [];
1078
+ function inspectFile(relative, transform) {
1079
+ const filePath = path4.resolve(packageInfo.rootPath, relative);
1080
+ if (!fs4.existsSync(filePath)) {
1081
+ checks.push({ relative, exists: false, patched: false });
1082
+ return;
1083
+ }
1084
+ const content = fs4.readFileSync(filePath, "utf8");
1085
+ const { hasPatched } = transform(content);
1086
+ checks.push({
1087
+ relative,
1088
+ exists: true,
1089
+ patched: hasPatched
1090
+ });
1091
+ }
1092
+ if (majorVersion === 3) {
1093
+ inspectFile("lib/processTailwindFeatures.js", transformProcessTailwindFeaturesReturnContext);
1094
+ const pluginCandidates = ["lib/plugin.js", "lib/index.js"];
1095
+ const pluginRelative = pluginCandidates.find((candidate) => fs4.existsSync(path4.resolve(packageInfo.rootPath, candidate)));
1096
+ if (pluginRelative) {
1097
+ inspectFile(pluginRelative, (content) => transformPostcssPlugin(content, { refProperty }));
1098
+ } else {
1099
+ checks.push({ relative: "lib/plugin.js", exists: false, patched: false });
1100
+ }
1101
+ } else {
1102
+ inspectFile("lib/jit/processTailwindFeatures.js", transformProcessTailwindFeaturesReturnContextV2);
1103
+ inspectFile("lib/jit/index.js", (content) => transformPostcssPluginV2(content, { refProperty }));
1104
+ }
1105
+ const files = checks.filter((check) => check.exists).map((check) => check.relative);
1106
+ const missingFiles = checks.filter((check) => !check.exists);
1107
+ const unpatchedFiles = checks.filter((check) => check.exists && !check.patched);
1108
+ const reasons = [];
1109
+ if (missingFiles.length) {
1110
+ reasons.push(`missing files: ${missingFiles.map((item) => item.relative).join(", ")}`);
1111
+ }
1112
+ if (unpatchedFiles.length) {
1113
+ reasons.push(`unpatched files: ${unpatchedFiles.map((item) => item.relative).join(", ")}`);
1114
+ }
1115
+ return {
1116
+ name: "exposeContext",
1117
+ status: reasons.length ? "not-applied" : "applied",
1118
+ reason: reasons.length ? reasons.join("; ") : void 0,
1119
+ files
1120
+ };
1121
+ }
1122
+ function checkExtendLengthUnitsV3(rootDir, options) {
1123
+ const lengthUnitsFilePath = options.lengthUnitsFilePath ?? "lib/util/dataTypes.js";
1124
+ const variableName = options.variableName ?? "lengthUnits";
1125
+ const target = path4.resolve(rootDir, lengthUnitsFilePath);
1126
+ const files = fs4.existsSync(target) ? [path4.relative(rootDir, target)] : [];
1127
+ if (!fs4.existsSync(target)) {
1128
+ return {
1129
+ name: "extendLengthUnits",
1130
+ status: "not-applied",
1131
+ reason: `missing ${lengthUnitsFilePath}`,
1132
+ files
1133
+ };
1134
+ }
1135
+ const content = fs4.readFileSync(target, "utf8");
1136
+ const { found, missingUnits } = inspectLengthUnitsArray(content, variableName, options.units);
1137
+ if (!found) {
1138
+ return {
1139
+ name: "extendLengthUnits",
1140
+ status: "not-applied",
1141
+ reason: `could not locate ${variableName} array in ${lengthUnitsFilePath}`,
1142
+ files
1143
+ };
1144
+ }
1145
+ if (missingUnits.length) {
1146
+ return {
1147
+ name: "extendLengthUnits",
1148
+ status: "not-applied",
1149
+ reason: `missing units: ${missingUnits.join(", ")}`,
1150
+ files
1151
+ };
1152
+ }
1153
+ return {
1154
+ name: "extendLengthUnits",
1155
+ status: "applied",
1156
+ files
1157
+ };
1158
+ }
1159
+ function checkExtendLengthUnitsV4(rootDir, options) {
1160
+ const distDir = path4.resolve(rootDir, "dist");
1161
+ if (!fs4.existsSync(distDir)) {
1162
+ return {
1163
+ name: "extendLengthUnits",
1164
+ status: "not-applied",
1165
+ reason: "dist directory not found for Tailwind v4 package",
1166
+ files: []
1167
+ };
1168
+ }
1169
+ const result = applyExtendLengthUnitsPatchV4(rootDir, {
1170
+ ...options,
1171
+ enabled: true,
1172
+ overwrite: false
1173
+ });
1174
+ if (result.files.length === 0) {
1175
+ return {
1176
+ name: "extendLengthUnits",
1177
+ status: "not-applied",
1178
+ reason: "no bundle chunks matched the length unit pattern",
1179
+ files: []
1180
+ };
1181
+ }
1182
+ const files = result.files.map((file) => path4.relative(rootDir, file.file));
1183
+ const pending = result.files.filter((file) => !file.hasPatched);
1184
+ if (pending.length) {
1185
+ return {
1186
+ name: "extendLengthUnits",
1187
+ status: "not-applied",
1188
+ reason: `missing units in ${pending.length} bundle${pending.length > 1 ? "s" : ""}`,
1189
+ files: pending.map((file) => path4.relative(rootDir, file.file))
1190
+ };
1191
+ }
1192
+ return {
1193
+ name: "extendLengthUnits",
1194
+ status: "applied",
1195
+ files
1196
+ };
1197
+ }
1198
+ function checkExtendLengthUnitsPatch(context) {
1199
+ const { packageInfo, options, majorVersion } = context;
1200
+ if (!options.features.extendLengthUnits) {
1201
+ return {
1202
+ name: "extendLengthUnits",
1203
+ status: "skipped",
1204
+ reason: "extendLengthUnits feature disabled",
1205
+ files: []
1206
+ };
1207
+ }
1208
+ if (majorVersion === 2) {
1209
+ return {
1210
+ name: "extendLengthUnits",
1211
+ status: "unsupported",
1212
+ reason: "length unit extension is only applied for Tailwind v3/v4",
1213
+ files: []
1214
+ };
1215
+ }
1216
+ if (majorVersion === 3) {
1217
+ return checkExtendLengthUnitsV3(packageInfo.rootPath, options.features.extendLengthUnits);
1218
+ }
1219
+ return checkExtendLengthUnitsV4(packageInfo.rootPath, options.features.extendLengthUnits);
1220
+ }
1221
+ function getPatchStatusReport(context) {
1222
+ return {
1223
+ package: {
1224
+ name: context.packageInfo.name ?? context.packageInfo.packageJson?.name,
1225
+ version: context.packageInfo.version,
1226
+ root: context.packageInfo.rootPath
1227
+ },
1228
+ majorVersion: context.majorVersion,
1229
+ entries: [
1230
+ checkExposeContextPatch(context),
1231
+ checkExtendLengthUnitsPatch(context)
1232
+ ]
1233
+ };
1234
+ }
1235
+
1236
+ // src/runtime/class-collector.ts
1237
+ import process4 from "process";
1238
+ import fs5 from "fs-extra";
1239
+ import path5 from "pathe";
1240
+ function collectClassesFromContexts(contexts, filter) {
1241
+ const set = /* @__PURE__ */ new Set();
1242
+ for (const context of contexts) {
1243
+ if (!isObject(context) || !context.classCache) {
1244
+ continue;
1245
+ }
1246
+ for (const key of context.classCache.keys()) {
1247
+ const className = key.toString();
1248
+ if (filter(className)) {
1249
+ set.add(className);
1250
+ }
1251
+ }
1252
+ }
1253
+ return set;
1254
+ }
1255
+ async function collectClassesFromTailwindV4(options) {
1256
+ const set = /* @__PURE__ */ new Set();
1257
+ const v4Options = options.tailwind.v4;
1258
+ if (!v4Options) {
1259
+ return set;
1260
+ }
1261
+ const toAbsolute = (value) => {
1262
+ if (!value) {
1263
+ return void 0;
1264
+ }
1265
+ return path5.isAbsolute(value) ? value : path5.resolve(options.projectRoot, value);
1266
+ };
1267
+ const resolvedConfiguredBase = toAbsolute(v4Options.configuredBase);
1268
+ const resolvedDefaultBase = toAbsolute(v4Options.base) ?? process4.cwd();
1269
+ const resolveSources = (base) => {
1270
+ if (!v4Options.sources?.length) {
1271
+ return void 0;
1272
+ }
1273
+ return v4Options.sources.map((source) => ({
1274
+ base: source.base ?? base,
1275
+ pattern: source.pattern,
1276
+ negated: source.negated
1277
+ }));
1278
+ };
1279
+ if (v4Options.cssEntries.length > 0) {
1280
+ for (const entry of v4Options.cssEntries) {
1281
+ const filePath = path5.isAbsolute(entry) ? entry : path5.resolve(options.projectRoot, entry);
1282
+ if (!await fs5.pathExists(filePath)) {
1283
+ continue;
1284
+ }
1285
+ const css = await fs5.readFile(filePath, "utf8");
1286
+ const entryDir = path5.dirname(filePath);
1287
+ const baseForEntry = resolvedConfiguredBase ?? entryDir;
1288
+ const sources = resolveSources(baseForEntry);
1289
+ const candidates = await extractValidCandidates({
1290
+ cwd: options.projectRoot,
1291
+ base: baseForEntry,
1292
+ css,
1293
+ sources
1294
+ });
1295
+ for (const candidate of candidates) {
1296
+ if (options.filter(candidate)) {
1297
+ set.add(candidate);
1298
+ }
1299
+ }
1300
+ }
1301
+ } else {
1302
+ const baseForCss = resolvedConfiguredBase ?? resolvedDefaultBase;
1303
+ const sources = resolveSources(baseForCss);
1304
+ const candidates = await extractValidCandidates({
1305
+ cwd: options.projectRoot,
1306
+ base: baseForCss,
1307
+ css: v4Options.css,
1308
+ sources
1309
+ });
1310
+ for (const candidate of candidates) {
1311
+ if (options.filter(candidate)) {
1312
+ set.add(candidate);
1313
+ }
1314
+ }
1315
+ }
1316
+ return set;
1317
+ }
1318
+
1319
+ // src/runtime/context-registry.ts
1320
+ import { createRequire } from "module";
1321
+ import fs6 from "fs-extra";
1322
+ import path6 from "pathe";
1323
+ var require2 = createRequire(import.meta.url);
1324
+ function resolveRuntimeEntry(packageInfo, majorVersion) {
1325
+ const root = packageInfo.rootPath;
1326
+ if (majorVersion === 2) {
1327
+ const jitIndex = path6.join(root, "lib/jit/index.js");
1328
+ if (fs6.existsSync(jitIndex)) {
1329
+ return jitIndex;
1330
+ }
1331
+ } else if (majorVersion === 3) {
1332
+ const plugin = path6.join(root, "lib/plugin.js");
1333
+ const index = path6.join(root, "lib/index.js");
1334
+ if (fs6.existsSync(plugin)) {
1335
+ return plugin;
1336
+ }
1337
+ if (fs6.existsSync(index)) {
1338
+ return index;
1339
+ }
1340
+ }
1341
+ return void 0;
1342
+ }
1343
+ function loadRuntimeContexts(packageInfo, majorVersion, refProperty) {
1344
+ if (majorVersion === 4) {
1345
+ return [];
1346
+ }
1347
+ const entry = resolveRuntimeEntry(packageInfo, majorVersion);
1348
+ if (!entry) {
1349
+ return [];
1350
+ }
1351
+ const moduleExports = require2(entry);
1352
+ if (!moduleExports) {
1353
+ return [];
1354
+ }
1355
+ const ref = moduleExports[refProperty];
1356
+ if (!ref) {
1357
+ return [];
1358
+ }
1359
+ if (Array.isArray(ref)) {
1360
+ return ref;
1361
+ }
1362
+ if (typeof ref === "object" && Array.isArray(ref.value)) {
1363
+ return ref.value;
1364
+ }
1365
+ return [];
1366
+ }
1367
+
1368
+ // src/runtime/process-tailwindcss.ts
1369
+ import { createRequire as createRequire2 } from "module";
1370
+ import path7 from "pathe";
1371
+ import postcss from "postcss";
1372
+ import { loadConfig } from "tailwindcss-config";
1373
+ var require3 = createRequire2(import.meta.url);
1374
+ async function resolveConfigPath(options) {
1375
+ if (options.config && path7.isAbsolute(options.config)) {
1376
+ return options.config;
1377
+ }
1378
+ const result = await loadConfig({ cwd: options.cwd });
1379
+ if (!result) {
1380
+ throw new Error(`Unable to locate Tailwind CSS config from ${options.cwd}`);
1381
+ }
1382
+ return result.filepath;
1383
+ }
1384
+ async function runTailwindBuild(options) {
1385
+ const configPath = await resolveConfigPath(options);
1386
+ const pluginName = options.postcssPlugin ?? (options.majorVersion === 4 ? "@tailwindcss/postcss" : "tailwindcss");
1387
+ if (options.majorVersion === 4) {
1388
+ return postcss([
1389
+ require3(pluginName)({
1390
+ config: configPath
1391
+ })
1392
+ ]).process("@import 'tailwindcss';", {
1393
+ from: void 0
1394
+ });
1395
+ }
1396
+ return postcss([
1397
+ require3(pluginName)({
1398
+ config: configPath
1399
+ })
1400
+ ]).process("@tailwind base;@tailwind components;@tailwind utilities;", {
1401
+ from: void 0
1402
+ });
1403
+ }
1404
+
1405
+ // src/api/tailwindcss-patcher.ts
1406
+ import process5 from "process";
1407
+ import fs8 from "fs-extra";
1408
+ import { getPackageInfoSync } from "local-pkg";
1409
+ import path9 from "pathe";
1410
+ import { coerce } from "semver";
1411
+
1412
+ // src/options/legacy.ts
1413
+ function normalizeLegacyFeatures(patch) {
1414
+ const apply = patch?.applyPatches;
1415
+ const extend = apply?.extendLengthUnits;
1416
+ let extendOption = false;
1417
+ if (extend && typeof extend === "object") {
1418
+ extendOption = {
1419
+ ...extend,
1420
+ enabled: true
1421
+ };
1422
+ } else if (extend === true) {
1423
+ extendOption = {
1424
+ enabled: true,
1425
+ units: ["rpx"],
1426
+ overwrite: patch?.overwrite
1427
+ };
1428
+ }
1429
+ return {
1430
+ exposeContext: apply?.exportContext ?? true,
1431
+ extendLengthUnits: extendOption
1432
+ };
1433
+ }
1434
+ function fromLegacyOptions(options) {
1435
+ if (!options) {
1436
+ return {};
1437
+ }
1438
+ const patch = options.patch;
1439
+ const features = normalizeLegacyFeatures(patch);
1440
+ const output = patch?.output;
1441
+ const tailwindConfig = patch?.tailwindcss;
1442
+ const tailwindVersion = tailwindConfig?.version;
1443
+ const tailwindV2 = tailwindConfig?.v2;
1444
+ const tailwindV3 = tailwindConfig?.v3;
1445
+ const tailwindV4 = tailwindConfig?.v4;
1446
+ const tailwindConfigPath = tailwindV3?.config ?? tailwindV2?.config;
1447
+ const tailwindCwd = tailwindV3?.cwd ?? tailwindV2?.cwd ?? patch?.cwd;
1448
+ return {
1449
+ cwd: patch?.cwd,
1450
+ overwrite: patch?.overwrite,
1451
+ filter: patch?.filter,
1452
+ cache: typeof options.cache === "boolean" ? options.cache : options.cache ? {
1453
+ ...options.cache,
1454
+ enabled: options.cache.enabled ?? true
1455
+ } : void 0,
1456
+ output: output ? {
1457
+ file: output.filename,
1458
+ pretty: output.loose ? 2 : false,
1459
+ removeUniversalSelector: output.removeUniversalSelector
1460
+ } : void 0,
1461
+ tailwind: {
1462
+ packageName: patch?.packageName,
1463
+ version: tailwindVersion,
1464
+ resolve: patch?.resolve,
1465
+ config: tailwindConfigPath,
1466
+ cwd: tailwindCwd,
1467
+ v2: tailwindV2,
1468
+ v3: tailwindV3,
1469
+ v4: tailwindV4
1470
+ },
1471
+ features: {
1472
+ exposeContext: features.exposeContext,
1473
+ extendLengthUnits: features.extendLengthUnits
1474
+ }
1475
+ };
1476
+ }
1477
+ function fromUnifiedConfig(registry) {
1478
+ if (!registry) {
1479
+ return {};
1480
+ }
1481
+ const tailwind = registry.tailwind;
1482
+ const output = registry.output;
1483
+ const pretty = (() => {
1484
+ if (output?.pretty === void 0) {
1485
+ return void 0;
1486
+ }
1487
+ if (typeof output.pretty === "boolean") {
1488
+ return output.pretty ? 2 : false;
1489
+ }
1490
+ return output.pretty;
1491
+ })();
1165
1492
  return {
1166
- code: hasPatched ? content : generate(ast).code,
1167
- hasPatched
1493
+ output: output ? {
1494
+ file: output.file,
1495
+ pretty,
1496
+ removeUniversalSelector: output.stripUniversalSelector
1497
+ } : void 0,
1498
+ tailwind: tailwind ? {
1499
+ version: tailwind.version,
1500
+ packageName: tailwind.package,
1501
+ resolve: tailwind.resolve,
1502
+ config: tailwind.config,
1503
+ cwd: tailwind.cwd,
1504
+ v2: tailwind.legacy,
1505
+ v3: tailwind.classic,
1506
+ v4: tailwind.next
1507
+ } : void 0
1168
1508
  };
1169
1509
  }
1170
1510
 
1171
1511
  // src/patching/operations/export-context/index.ts
1512
+ import fs7 from "fs-extra";
1513
+ import path8 from "pathe";
1172
1514
  function writeFileIfRequired(filePath, code, overwrite, successMessage) {
1173
1515
  if (!overwrite) {
1174
1516
  return;
1175
1517
  }
1176
- fs5.writeFileSync(filePath, code, {
1518
+ fs7.writeFileSync(filePath, code, {
1177
1519
  encoding: "utf8"
1178
1520
  });
1179
1521
  logger_default.success(successMessage);
@@ -1186,9 +1528,9 @@ function applyExposeContextPatch(params) {
1186
1528
  };
1187
1529
  if (majorVersion === 3) {
1188
1530
  const processFileRelative = "lib/processTailwindFeatures.js";
1189
- const processFilePath = path6.resolve(rootDir, processFileRelative);
1190
- if (fs5.existsSync(processFilePath)) {
1191
- const content = fs5.readFileSync(processFilePath, "utf8");
1531
+ const processFilePath = path8.resolve(rootDir, processFileRelative);
1532
+ if (fs7.existsSync(processFilePath)) {
1533
+ const content = fs7.readFileSync(processFilePath, "utf8");
1192
1534
  const { code, hasPatched } = transformProcessTailwindFeaturesReturnContext(content);
1193
1535
  result.files[processFileRelative] = code;
1194
1536
  if (!hasPatched) {
@@ -1202,10 +1544,10 @@ function applyExposeContextPatch(params) {
1202
1544
  }
1203
1545
  }
1204
1546
  const pluginCandidates = ["lib/plugin.js", "lib/index.js"];
1205
- const pluginRelative = pluginCandidates.find((candidate) => fs5.existsSync(path6.resolve(rootDir, candidate)));
1547
+ const pluginRelative = pluginCandidates.find((candidate) => fs7.existsSync(path8.resolve(rootDir, candidate)));
1206
1548
  if (pluginRelative) {
1207
- const pluginPath = path6.resolve(rootDir, pluginRelative);
1208
- const content = fs5.readFileSync(pluginPath, "utf8");
1549
+ const pluginPath = path8.resolve(rootDir, pluginRelative);
1550
+ const content = fs7.readFileSync(pluginPath, "utf8");
1209
1551
  const { code, hasPatched } = transformPostcssPlugin(content, { refProperty });
1210
1552
  result.files[pluginRelative] = code;
1211
1553
  if (!hasPatched) {
@@ -1220,9 +1562,9 @@ function applyExposeContextPatch(params) {
1220
1562
  }
1221
1563
  } else if (majorVersion === 2) {
1222
1564
  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");
1565
+ const processFilePath = path8.resolve(rootDir, processFileRelative);
1566
+ if (fs7.existsSync(processFilePath)) {
1567
+ const content = fs7.readFileSync(processFilePath, "utf8");
1226
1568
  const { code, hasPatched } = transformProcessTailwindFeaturesReturnContextV2(content);
1227
1569
  result.files[processFileRelative] = code;
1228
1570
  if (!hasPatched) {
@@ -1236,9 +1578,9 @@ function applyExposeContextPatch(params) {
1236
1578
  }
1237
1579
  }
1238
1580
  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");
1581
+ const pluginPath = path8.resolve(rootDir, pluginRelative);
1582
+ if (fs7.existsSync(pluginPath)) {
1583
+ const content = fs7.readFileSync(pluginPath, "utf8");
1242
1584
  const { code, hasPatched } = transformPostcssPluginV2(content, { refProperty });
1243
1585
  result.files[pluginRelative] = code;
1244
1586
  if (!hasPatched) {
@@ -1255,147 +1597,6 @@ function applyExposeContextPatch(params) {
1255
1597
  return result;
1256
1598
  }
1257
1599
 
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
1600
  // src/patching/patch-runner.ts
1400
1601
  function applyTailwindPatches(context) {
1401
1602
  const { packageInfo, options, majorVersion } = context;
@@ -1494,6 +1695,13 @@ var TailwindcssPatcher = class {
1494
1695
  majorVersion: this.majorVersion
1495
1696
  });
1496
1697
  }
1698
+ async getPatchStatus() {
1699
+ return getPatchStatusReport({
1700
+ packageInfo: this.packageInfo,
1701
+ options: this.options,
1702
+ majorVersion: this.majorVersion
1703
+ });
1704
+ }
1497
1705
  getContexts() {
1498
1706
  return loadRuntimeContexts(
1499
1707
  this.packageInfo,
@@ -1585,13 +1793,13 @@ var TailwindcssPatcher = class {
1585
1793
  if (!shouldWrite || !this.options.output.file) {
1586
1794
  return result;
1587
1795
  }
1588
- const target = path8.resolve(this.options.output.file);
1589
- await fs7.ensureDir(path8.dirname(target));
1796
+ const target = path9.resolve(this.options.output.file);
1797
+ await fs8.ensureDir(path9.dirname(target));
1590
1798
  if (this.options.output.format === "json") {
1591
1799
  const spaces = typeof this.options.output.pretty === "number" ? this.options.output.pretty : void 0;
1592
- await fs7.writeJSON(target, classList, { spaces });
1800
+ await fs8.writeJSON(target, classList, { spaces });
1593
1801
  } else {
1594
- await fs7.writeFile(target, `${classList.join("\n")}
1802
+ await fs8.writeFile(target, `${classList.join("\n")}
1595
1803
  `, "utf8");
1596
1804
  }
1597
1805
  logger_default.success(`Tailwind CSS class list saved to ${target.replace(process5.cwd(), ".")}`);
@@ -1716,9 +1924,9 @@ var acceptChars = [..."abcdefghijklmnopqrstuvwxyz"];
1716
1924
 
1717
1925
  // src/cli/commands.ts
1718
1926
  import cac from "cac";
1719
- import fs8 from "fs-extra";
1720
- import path9 from "pathe";
1721
- var tailwindcssPatchCommands = ["install", "extract", "tokens", "init"];
1927
+ import fs9 from "fs-extra";
1928
+ import path10 from "pathe";
1929
+ var tailwindcssPatchCommands = ["install", "extract", "tokens", "init", "status"];
1722
1930
  var TOKEN_FORMATS = ["json", "lines", "grouped-json"];
1723
1931
  var DEFAULT_TOKEN_REPORT = ".tw-patch/tw-token-report.json";
1724
1932
  function formatTokenLine(entry) {
@@ -1744,7 +1952,7 @@ function resolveCwd(rawCwd) {
1744
1952
  if (!rawCwd) {
1745
1953
  return process6.cwd();
1746
1954
  }
1747
- return path9.resolve(rawCwd);
1955
+ return path10.resolve(rawCwd);
1748
1956
  }
1749
1957
  function createDefaultRunner(factory) {
1750
1958
  let promise;
@@ -1846,6 +2054,13 @@ function buildDefaultCommandDefinitions() {
1846
2054
  init: {
1847
2055
  description: "Generate a tailwindcss-patch config file",
1848
2056
  optionDefs: [createCwdOptionDefinition()]
2057
+ },
2058
+ status: {
2059
+ description: "Check which Tailwind patches are applied",
2060
+ optionDefs: [
2061
+ createCwdOptionDefinition(),
2062
+ { flags: "--json", description: "Print a JSON report of patch status" }
2063
+ ]
1849
2064
  }
1850
2065
  };
1851
2066
  }
@@ -1949,15 +2164,15 @@ async function tokensCommandDefaultHandler(ctx) {
1949
2164
  const grouped = format === "grouped-json" ? buildGrouped() : null;
1950
2165
  const resolveGrouped = () => grouped ?? buildGrouped();
1951
2166
  if (shouldWrite) {
1952
- const target = path9.resolve(targetFile);
1953
- await fs8.ensureDir(path9.dirname(target));
2167
+ const target = path10.resolve(targetFile);
2168
+ await fs9.ensureDir(path10.dirname(target));
1954
2169
  if (format === "json") {
1955
- await fs8.writeJSON(target, report, { spaces: 2 });
2170
+ await fs9.writeJSON(target, report, { spaces: 2 });
1956
2171
  } else if (format === "grouped-json") {
1957
- await fs8.writeJSON(target, resolveGrouped(), { spaces: 2 });
2172
+ await fs9.writeJSON(target, resolveGrouped(), { spaces: 2 });
1958
2173
  } else {
1959
2174
  const lines = report.entries.map(formatTokenLine);
1960
- await fs8.writeFile(target, `${lines.join("\n")}
2175
+ await fs9.writeFile(target, `${lines.join("\n")}
1961
2176
  `, "utf8");
1962
2177
  }
1963
2178
  logger_default.success(`Collected ${report.entries.length} tokens (${format}) \u2192 ${target.replace(process6.cwd(), ".")}`);
@@ -2002,6 +2217,46 @@ async function initCommandDefaultHandler(ctx) {
2002
2217
  await initConfig(ctx.cwd);
2003
2218
  logger_default.success(`\u2728 ${CONFIG_NAME}.config.ts initialized!`);
2004
2219
  }
2220
+ function formatFilesHint(entry) {
2221
+ if (!entry.files.length) {
2222
+ return "";
2223
+ }
2224
+ return ` (${entry.files.join(", ")})`;
2225
+ }
2226
+ async function statusCommandDefaultHandler(ctx) {
2227
+ const patcher = await ctx.createPatcher();
2228
+ const report = await patcher.getPatchStatus();
2229
+ if (ctx.args.json) {
2230
+ logger_default.log(JSON.stringify(report, null, 2));
2231
+ return report;
2232
+ }
2233
+ const applied = report.entries.filter((entry) => entry.status === "applied");
2234
+ const pending = report.entries.filter((entry) => entry.status === "not-applied");
2235
+ const skipped = report.entries.filter((entry) => entry.status === "skipped" || entry.status === "unsupported");
2236
+ const packageLabel = `${report.package.name ?? "tailwindcss"}@${report.package.version ?? "unknown"}`;
2237
+ logger_default.info(`Patch status for ${packageLabel} (v${report.majorVersion})`);
2238
+ if (applied.length) {
2239
+ logger_default.success("Applied:");
2240
+ applied.forEach((entry) => logger_default.success(` \u2022 ${entry.name}${formatFilesHint(entry)}`));
2241
+ }
2242
+ if (pending.length) {
2243
+ logger_default.warn("Needs attention:");
2244
+ pending.forEach((entry) => {
2245
+ const details = entry.reason ? ` \u2013 ${entry.reason}` : "";
2246
+ logger_default.warn(` \u2022 ${entry.name}${formatFilesHint(entry)}${details}`);
2247
+ });
2248
+ } else {
2249
+ logger_default.success("All applicable patches are applied.");
2250
+ }
2251
+ if (skipped.length) {
2252
+ logger_default.info("Skipped:");
2253
+ skipped.forEach((entry) => {
2254
+ const details = entry.reason ? ` \u2013 ${entry.reason}` : "";
2255
+ logger_default.info(` \u2022 ${entry.name}${details}`);
2256
+ });
2257
+ }
2258
+ return report;
2259
+ }
2005
2260
  function mountTailwindcssPatchCommands(cli, options = {}) {
2006
2261
  const prefix = options.commandPrefix ?? "";
2007
2262
  const selectedCommands = options.commands ?? tailwindcssPatchCommands;
@@ -2070,6 +2325,22 @@ function mountTailwindcssPatchCommands(cli, options = {}) {
2070
2325
  );
2071
2326
  });
2072
2327
  metadata.aliases.forEach((alias) => command.alias(alias));
2328
+ },
2329
+ status: () => {
2330
+ const metadata = resolveCommandMetadata("status", options, prefix, defaultDefinitions);
2331
+ const command = cli.command(metadata.name, metadata.description);
2332
+ applyCommandOptions(command, metadata.optionDefs);
2333
+ command.action(async (args) => {
2334
+ return runWithCommandHandler(
2335
+ cli,
2336
+ command,
2337
+ "status",
2338
+ args,
2339
+ options.commandHandlers?.status,
2340
+ statusCommandDefaultHandler
2341
+ );
2342
+ });
2343
+ metadata.aliases.forEach((alias) => command.alias(alias));
2073
2344
  }
2074
2345
  };
2075
2346
  for (const name of selectedCommands) {
@@ -2095,6 +2366,7 @@ export {
2095
2366
  extractProjectCandidatesWithPositions,
2096
2367
  groupTokensByFile,
2097
2368
  normalizeOptions,
2369
+ getPatchStatusReport,
2098
2370
  collectClassesFromContexts,
2099
2371
  collectClassesFromTailwindV4,
2100
2372
  loadRuntimeContexts,