@weapp-tailwindcss/postcss 3.2.3 → 3.2.4

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.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 将常见预处理器风格的行注释转换为 PostCSS 可解析的块注释。
3
+ * 避免改写字符串、块注释和未加引号的 URL。
4
+ */
5
+ export declare function normalizeCssLineComments(source: string): string;
@@ -0,0 +1,4 @@
1
+ import type { Result as PostcssResult } from 'postcss';
2
+ import type postcss from 'postcss';
3
+ export declare function isUvueSfcStyleRequest(result: PostcssResult): boolean;
4
+ export declare function stripScopedTailwindNoise(root: postcss.Root): void;
@@ -1,4 +1,4 @@
1
1
  import type { Result as PostcssResult } from 'postcss';
2
2
  import type { IStyleHandlerOptions } from '../types.js';
3
3
  import postcss from 'postcss';
4
- export declare function applyUniAppXUvueCompatibility(result: PostcssResult, options?: Pick<IStyleHandlerOptions, 'customPropertyValues' | 'uniAppX' | 'uniAppXCssTarget' | 'uniAppXUnsupported'>): PostcssResult<postcss.Document | postcss.Root>;
4
+ export declare function applyUniAppXUvueCompatibility(result: PostcssResult, options?: Pick<IStyleHandlerOptions, 'customPropertyValues' | 'isMainChunk' | 'uniAppX' | 'uniAppXCssTarget' | 'uniAppXUnsupported'>): PostcssResult<postcss.Document | postcss.Root>;
package/dist/index.cjs CHANGED
@@ -816,6 +816,197 @@ function isTailwindcssV4DisplayP3Declaration(decl) {
816
816
  return DISPLAY_P3_VALUE_RE$1.test(decl.value);
817
817
  }
818
818
  //#endregion
819
+ //#region src/compat/uni-app-x-uvue/scoped-style.ts
820
+ const MINI_PROGRAM_PREFLIGHT_SELECTORS$1 = /* @__PURE__ */ new Set([
821
+ "view",
822
+ "text",
823
+ "::after",
824
+ "::before"
825
+ ]);
826
+ const SCOPED_UNIVERSAL_PREFLIGHT_SELECTORS = /* @__PURE__ */ new Set([
827
+ "*",
828
+ "::after",
829
+ "::before",
830
+ "::backdrop",
831
+ "::file-selector-button"
832
+ ]);
833
+ const TAILWIND_VERSION_COMMENT_RE = /tailwindcss v\d/i;
834
+ const VUE_SCOPED_ATTR_RE = /\[data-v-[^\]]+\]/gi;
835
+ const VUE_SCOPED_CLASS_RE = /\.data-v-[\w-]+/gi;
836
+ const TAILWIND_PREFLIGHT_DECLARATIONS = /* @__PURE__ */ new Set([
837
+ "-moz-tab-size:4",
838
+ "-webkit-appearance:none",
839
+ "-webkit-appearance:button",
840
+ "-webkit-tap-highlight-color:transparent",
841
+ "-webkit-text-decoration:inherit",
842
+ "-webkit-text-decoration:underline dotted",
843
+ "-webkit-text-size-adjust:100%",
844
+ "-o-tab-size:4",
845
+ "appearance:button",
846
+ "background-color:transparent",
847
+ "border-collapse:collapse",
848
+ "border-color:inherit",
849
+ "border-radius:0",
850
+ "border-top-width:1px",
851
+ "bottom:-.25em",
852
+ "color:inherit",
853
+ "display:block",
854
+ "display:inline-flex",
855
+ "display:list-item",
856
+ "font:inherit",
857
+ "font-family:inherit",
858
+ "font-feature-settings:inherit",
859
+ "font-size:1em",
860
+ "font-size:75%",
861
+ "font-size:80%",
862
+ "font-size:inherit",
863
+ "font-variation-settings:inherit",
864
+ "font-weight:bolder",
865
+ "font-weight:inherit",
866
+ "height:0",
867
+ "height:auto",
868
+ "letter-spacing:inherit",
869
+ "line-height:1",
870
+ "line-height:1.5",
871
+ "line-height:0",
872
+ "line-height:inherit",
873
+ "list-style:none",
874
+ "margin-inline-end:4px",
875
+ "max-width:100%",
876
+ "min-height:1lh",
877
+ "opacity:1",
878
+ "outline:auto",
879
+ "padding:0",
880
+ "padding-block:0",
881
+ "position:relative",
882
+ "resize:vertical",
883
+ "tab-size:4",
884
+ "text-align:inherit",
885
+ "text-decoration:inherit",
886
+ "text-decoration:underline dotted",
887
+ "text-indent:0",
888
+ "text-transform:none",
889
+ "top:-.5em",
890
+ "vertical-align:baseline",
891
+ "vertical-align:middle"
892
+ ]);
893
+ function hasVueScopedAttr(value) {
894
+ VUE_SCOPED_ATTR_RE.lastIndex = 0;
895
+ VUE_SCOPED_CLASS_RE.lastIndex = 0;
896
+ const matched = VUE_SCOPED_ATTR_RE.test(value) || VUE_SCOPED_CLASS_RE.test(value);
897
+ VUE_SCOPED_ATTR_RE.lastIndex = 0;
898
+ VUE_SCOPED_CLASS_RE.lastIndex = 0;
899
+ return matched;
900
+ }
901
+ function normalizeCssSignatureValue(value) {
902
+ return value.replace(VUE_SCOPED_ATTR_RE, "").replace(VUE_SCOPED_CLASS_RE, "").replace(/\s+/g, " ").replace(/\s*([>+~])\s*/g, "$1").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").trim();
903
+ }
904
+ function isSfcStyleRequestSource(source) {
905
+ if (typeof source !== "string") return false;
906
+ const queryIndex = source.indexOf("?");
907
+ if (queryIndex < 0 || !source.slice(0, queryIndex).toLowerCase().endsWith(".uvue")) return false;
908
+ const hashIndex = source.indexOf("#", queryIndex);
909
+ const query = source.slice(queryIndex + 1, hashIndex < 0 ? void 0 : hashIndex);
910
+ return new URLSearchParams(query).get("type") === "style";
911
+ }
912
+ function isUvueSfcStyleRequest(result) {
913
+ if (isSfcStyleRequestSource(result.opts.from)) return true;
914
+ if ((result.root.nodes ?? []).some((node) => isSfcStyleRequestSource(node.source?.input.from))) return true;
915
+ let hasScopedSelector = false;
916
+ result.root.walkRules((rule) => {
917
+ if ((rule.selectors ?? [rule.selector]).some(hasVueScopedAttr)) {
918
+ hasScopedSelector = true;
919
+ return false;
920
+ }
921
+ });
922
+ return hasScopedSelector;
923
+ }
924
+ function getDeclarations(rule) {
925
+ return rule.nodes?.filter((node) => node.type === "decl") ?? [];
926
+ }
927
+ function isLikelyTailwindGlobalSelector(selector) {
928
+ const normalized = normalizeCssSignatureValue(selector);
929
+ return normalized === "*" || normalized.startsWith("::") || normalized.startsWith(":root") || normalized.startsWith(":host") || /^(?:html|body|hr|abbr|h1|h2|h3|h4|h5|h6|a|b|strong|code|kbd|samp|pre|small|sub|sup|table|button|input|select|optgroup|textarea|summary|blockquote|dl|dd|fieldset|legend|ol|ul|menu|dialog|progress|video|audio|canvas|embed|iframe|img|object|svg|details|template|[uo]ni-progress)(?:$|[:,[\s>+~.#])/.test(normalized);
930
+ }
931
+ function isTailwindPreflightDeclaration(decl) {
932
+ const prop = decl.prop.trim().toLowerCase();
933
+ const value = normalizeCssSignatureValue(decl.value.trim().toLowerCase());
934
+ if (prop.startsWith("--tw-")) return true;
935
+ if (prop === "color" && value.startsWith("color-mix(") && value.includes("currentcolor") && value.includes("transparent")) return true;
936
+ if (prop === "color" && value === "currentcolor") return true;
937
+ if (prop === "font-family" && value.startsWith("var(--default-font-family") || prop === "font-feature-settings" && value.startsWith("var(--default-font-feature-settings") || prop === "font-variation-settings" && value.startsWith("var(--default-font-variation-settings")) return true;
938
+ return TAILWIND_PREFLIGHT_DECLARATIONS.has(`${prop}:${value}`);
939
+ }
940
+ function isScopedTailwindThemeCarrierRule(rule) {
941
+ const selectors = rule.selectors ?? [rule.selector];
942
+ const declarations = getDeclarations(rule);
943
+ return selectors.length > 0 && selectors.every((selector) => {
944
+ const normalized = normalizeCssSignatureValue(selector);
945
+ return hasVueScopedAttr(selector) && (normalized.startsWith(":root") || normalized.startsWith(":host"));
946
+ }) && declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--"));
947
+ }
948
+ function isScopedUniversalTailwindPreflightRule(rule) {
949
+ const selectors = rule.selectors ?? [rule.selector];
950
+ const declarations = getDeclarations(rule);
951
+ return selectors.length > 0 && selectors.every((selector) => hasVueScopedAttr(selector) && SCOPED_UNIVERSAL_PREFLIGHT_SELECTORS.has(normalizeCssSignatureValue(selector))) && declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--tw-") || [
952
+ "box-sizing",
953
+ "margin",
954
+ "padding",
955
+ "border"
956
+ ].includes(decl.prop));
957
+ }
958
+ function isScopedTailwindElementPreflightRule(rule, hasTailwindBanner) {
959
+ if (!hasTailwindBanner) return false;
960
+ const selectors = rule.selectors ?? [rule.selector];
961
+ const declarations = getDeclarations(rule);
962
+ return selectors.length > 0 && selectors.every((selector) => hasVueScopedAttr(selector) && isLikelyTailwindGlobalSelector(selector)) && declarations.length > 0 && declarations.every(isTailwindPreflightDeclaration);
963
+ }
964
+ function isUnscopedMiniProgramTailwindPreflightRule(rule) {
965
+ const selectors = rule.selectors ?? [rule.selector];
966
+ if (selectors.length === 0 || !selectors.every((selector) => {
967
+ const normalized = normalizeCssSignatureValue(selector);
968
+ return !hasVueScopedAttr(selector) && MINI_PROGRAM_PREFLIGHT_SELECTORS$1.has(normalized);
969
+ })) return false;
970
+ const declarations = getDeclarations(rule);
971
+ return declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--tw-") || [
972
+ "box-sizing",
973
+ "margin",
974
+ "padding",
975
+ "border"
976
+ ].includes(decl.prop));
977
+ }
978
+ function isScopedMiniProgramTailwindContentInitRule(rule) {
979
+ const selectors = rule.selectors ?? [rule.selector];
980
+ if (selectors.length === 0 || !selectors.every((selector) => {
981
+ const normalized = normalizeCssSignatureValue(selector);
982
+ return hasVueScopedAttr(selector) && MINI_PROGRAM_PREFLIGHT_SELECTORS$1.has(normalized);
983
+ })) return false;
984
+ const declarations = getDeclarations(rule);
985
+ return declarations.length > 0 && declarations.every((decl) => decl.prop === "--tw-content");
986
+ }
987
+ function isLikelyTailwindPropertyAtRule(atRule) {
988
+ return typeof atRule.name === "string" && atRule.name.toLowerCase() === "property" && normalizeCssSignatureValue(atRule.params).startsWith("--tw-");
989
+ }
990
+ function stripScopedTailwindNoise(root) {
991
+ let hasTailwindBanner = false;
992
+ root.walkComments((comment) => {
993
+ if (TAILWIND_VERSION_COMMENT_RE.test(comment.text)) hasTailwindBanner = true;
994
+ });
995
+ root.walkComments((comment) => {
996
+ if (TAILWIND_VERSION_COMMENT_RE.test(comment.text)) comment.remove();
997
+ });
998
+ root.walkRules((rule) => {
999
+ if (isScopedTailwindThemeCarrierRule(rule) || isScopedUniversalTailwindPreflightRule(rule) || isScopedTailwindElementPreflightRule(rule, hasTailwindBanner) || isUnscopedMiniProgramTailwindPreflightRule(rule) || isScopedMiniProgramTailwindContentInitRule(rule)) rule.remove();
1000
+ });
1001
+ root.walkAtRules((atRule) => {
1002
+ if (isLikelyTailwindPropertyAtRule(atRule)) {
1003
+ atRule.remove();
1004
+ return;
1005
+ }
1006
+ if ((atRule.nodes?.length ?? 0) === 0) atRule.remove();
1007
+ });
1008
+ }
1009
+ //#endregion
819
1010
  //#region src/compat/uni-app-x-uvue/theme.ts
820
1011
  const SYSTEM_ROOT_SELECTORS = /* @__PURE__ */ new Set([
821
1012
  ":host",
@@ -1013,6 +1204,7 @@ function applyUniAppXUvueCompatibility(result, options) {
1013
1204
  if (!isUniAppXUvueTarget(options)) return result;
1014
1205
  const mode = normalizeUnsupportedMode(options?.uniAppXUnsupported);
1015
1206
  const warningCache = /* @__PURE__ */ new Set();
1207
+ const sfcStyleRequest = options?.isMainChunk !== true && isUvueSfcStyleRequest(result);
1016
1208
  let root = result.root;
1017
1209
  let calcMessages = [];
1018
1210
  consumeUniAppXSystemRootTheme(root, options?.customPropertyValues);
@@ -1025,8 +1217,9 @@ function applyUniAppXUvueCompatibility(result, options) {
1025
1217
  root = calcResult.root;
1026
1218
  calcMessages = calcResult.messages;
1027
1219
  }
1220
+ if (sfcStyleRequest) stripScopedTailwindNoise(root);
1028
1221
  root.walkRules((rule) => {
1029
- if (!hasOnlyClassSelectors(rule)) {
1222
+ if (!sfcStyleRequest && !hasOnlyClassSelectors(rule)) {
1030
1223
  reportUnsupportedRule(rule, result, mode, warningCache, "selector must be class-only");
1031
1224
  rule.remove();
1032
1225
  return;
@@ -4275,6 +4468,81 @@ function rewriteLocalCssImportRequestsForOutput(css, options = {}) {
4275
4468
  }
4276
4469
  }
4277
4470
  //#endregion
4471
+ //#region src/compat/line-comments.ts
4472
+ /**
4473
+ * 将常见预处理器风格的行注释转换为 PostCSS 可解析的块注释。
4474
+ * 避免改写字符串、块注释和未加引号的 URL。
4475
+ */
4476
+ function normalizeCssLineComments(source) {
4477
+ if (!source.includes("//")) return source;
4478
+ const parts = [];
4479
+ let lastWriteIndex = 0;
4480
+ const syntaxCharacter = /[/"'(]/g;
4481
+ for (let match = syntaxCharacter.exec(source); match; match = syntaxCharacter.exec(source)) {
4482
+ const index = match.index;
4483
+ const char = match[0];
4484
+ const next = source[index + 1];
4485
+ if (char === "/" && next === "*" && !isEscaped(source, index)) {
4486
+ const commentEnd = source.indexOf("*/", index + 2);
4487
+ syntaxCharacter.lastIndex = commentEnd === -1 ? source.length : commentEnd + 2;
4488
+ continue;
4489
+ }
4490
+ if ((char === "\"" || char === "'") && !isEscaped(source, index)) {
4491
+ const quoteEnd = findUnescapedCharacter(source, char, index + 1);
4492
+ syntaxCharacter.lastIndex = quoteEnd === -1 ? source.length : quoteEnd + 1;
4493
+ continue;
4494
+ }
4495
+ if (char === "(" && isUrlFunctionStart(source, index)) {
4496
+ let valueStart = index + 1;
4497
+ while (valueStart < source.length && /\s/.test(source[valueStart] ?? "")) valueStart++;
4498
+ const valueStartChar = source[valueStart];
4499
+ if (valueStartChar !== "\"" && valueStartChar !== "'") {
4500
+ const urlEnd = findUnescapedCharacter(source, ")", valueStart);
4501
+ syntaxCharacter.lastIndex = urlEnd === -1 ? source.length : urlEnd + 1;
4502
+ }
4503
+ continue;
4504
+ }
4505
+ if (char === "/" && next === "/" && !isEscaped(source, index)) {
4506
+ let lineStart = index - 1;
4507
+ while (lineStart >= 0 && source[lineStart] !== "\n" && source[lineStart] !== "\r") lineStart--;
4508
+ const linePrefix = source.slice(lineStart + 1, index);
4509
+ const trimmedLinePrefix = linePrefix.trimEnd();
4510
+ const needsSemicolon = trimmedLinePrefix.length > 0 && !/[;{}]$/.test(trimmedLinePrefix);
4511
+ let unchangedPrefix = source.slice(lastWriteIndex, index);
4512
+ if (needsSemicolon) {
4513
+ const trailingWhitespaceLength = linePrefix.length - trimmedLinePrefix.length;
4514
+ const insertionIndex = unchangedPrefix.length - trailingWhitespaceLength;
4515
+ unchangedPrefix = `${unchangedPrefix.slice(0, insertionIndex)};${unchangedPrefix.slice(insertionIndex)}`;
4516
+ }
4517
+ let lineEnd = index + 2;
4518
+ while (lineEnd < source.length && source[lineEnd] !== "\n" && source[lineEnd] !== "\r") lineEnd++;
4519
+ parts.push(unchangedPrefix, "/*", source.slice(index + 2, lineEnd), "*/");
4520
+ lastWriteIndex = lineEnd;
4521
+ syntaxCharacter.lastIndex = lineEnd;
4522
+ continue;
4523
+ }
4524
+ }
4525
+ if (parts.length === 0) return source;
4526
+ parts.push(source.slice(lastWriteIndex));
4527
+ return parts.join("");
4528
+ }
4529
+ function isEscaped(source, index) {
4530
+ let backslashCount = 0;
4531
+ for (let cursor = index - 1; cursor >= 0 && source[cursor] === "\\"; cursor--) backslashCount++;
4532
+ return backslashCount % 2 === 1;
4533
+ }
4534
+ function findUnescapedCharacter(source, character, fromIndex) {
4535
+ let index = source.indexOf(character, fromIndex);
4536
+ while (index !== -1 && isEscaped(source, index)) index = source.indexOf(character, index + 1);
4537
+ return index;
4538
+ }
4539
+ function isUrlFunctionStart(source, index) {
4540
+ if (isEscaped(source, index) || index < 3) return false;
4541
+ const prefix = source.slice(index - 3, index);
4542
+ const beforePrefix = source[index - 4];
4543
+ return prefix.toLowerCase() === "url" && (beforePrefix === void 0 || !/\w/.test(beforePrefix));
4544
+ }
4545
+ //#endregion
4278
4546
  //#region src/content-probe.ts
4279
4547
  /**
4280
4548
  * 所有标志均为 false 的空信号
@@ -6459,14 +6727,15 @@ function createStyleHandler(options) {
6459
6727
  }
6460
6728
  function processSource(rawSource, root, cloneOutput, opt) {
6461
6729
  const resolvedOptions = resolver.resolve(opt);
6730
+ const normalizedRawSource = normalizeCssLineComments(rawSource);
6462
6731
  const isUniAppXFramework = resolvedOptions.appType === "uni-app-x";
6463
- const protectedVarFallbacks = resolvedOptions.uniAppX || isUniAppXFramework ? protectDynamicVarFallbacks(rawSource) : {
6464
- css: rawSource,
6732
+ const protectedVarFallbacks = resolvedOptions.uniAppX || isUniAppXFramework ? protectDynamicVarFallbacks(normalizedRawSource) : {
6733
+ css: normalizedRawSource,
6465
6734
  restore: (value) => value
6466
6735
  };
6467
6736
  const protectedColorMix = resolvedOptions.majorVersion === 4 ? protectDynamicColorMixAlpha(protectedVarFallbacks.css) : void 0;
6468
6737
  const source = protectedColorMix?.css ?? protectedVarFallbacks.css;
6469
- const processInput = source !== rawSource ? source : root?.clone() ?? source;
6738
+ const processInput = source !== normalizedRawSource ? source : root?.clone() ?? source;
6470
6739
  let signal;
6471
6740
  if (!hasUserPlugins) try {
6472
6741
  signal = probeFeatures(source);
@@ -6493,7 +6762,7 @@ function createStyleHandler(options) {
6493
6762
  finalResult = nextResult;
6494
6763
  }
6495
6764
  }
6496
- if (protectedColorMix || protectedVarFallbacks.css !== rawSource) {
6765
+ if (protectedColorMix || protectedVarFallbacks.css !== normalizedRawSource) {
6497
6766
  const restoredCss = protectedVarFallbacks.restore(protectedColorMix?.restore(finalResult.css) ?? finalResult.css);
6498
6767
  if (restoredCss !== finalResult.css) {
6499
6768
  const nextResult = finalResult.root.clone().toResult(finalResult.opts);
package/dist/index.js CHANGED
@@ -801,6 +801,197 @@ function isTailwindcssV4DisplayP3Declaration(decl) {
801
801
  return DISPLAY_P3_VALUE_RE$1.test(decl.value);
802
802
  }
803
803
  //#endregion
804
+ //#region src/compat/uni-app-x-uvue/scoped-style.ts
805
+ const MINI_PROGRAM_PREFLIGHT_SELECTORS$1 = /* @__PURE__ */ new Set([
806
+ "view",
807
+ "text",
808
+ "::after",
809
+ "::before"
810
+ ]);
811
+ const SCOPED_UNIVERSAL_PREFLIGHT_SELECTORS = /* @__PURE__ */ new Set([
812
+ "*",
813
+ "::after",
814
+ "::before",
815
+ "::backdrop",
816
+ "::file-selector-button"
817
+ ]);
818
+ const TAILWIND_VERSION_COMMENT_RE = /tailwindcss v\d/i;
819
+ const VUE_SCOPED_ATTR_RE = /\[data-v-[^\]]+\]/gi;
820
+ const VUE_SCOPED_CLASS_RE = /\.data-v-[\w-]+/gi;
821
+ const TAILWIND_PREFLIGHT_DECLARATIONS = /* @__PURE__ */ new Set([
822
+ "-moz-tab-size:4",
823
+ "-webkit-appearance:none",
824
+ "-webkit-appearance:button",
825
+ "-webkit-tap-highlight-color:transparent",
826
+ "-webkit-text-decoration:inherit",
827
+ "-webkit-text-decoration:underline dotted",
828
+ "-webkit-text-size-adjust:100%",
829
+ "-o-tab-size:4",
830
+ "appearance:button",
831
+ "background-color:transparent",
832
+ "border-collapse:collapse",
833
+ "border-color:inherit",
834
+ "border-radius:0",
835
+ "border-top-width:1px",
836
+ "bottom:-.25em",
837
+ "color:inherit",
838
+ "display:block",
839
+ "display:inline-flex",
840
+ "display:list-item",
841
+ "font:inherit",
842
+ "font-family:inherit",
843
+ "font-feature-settings:inherit",
844
+ "font-size:1em",
845
+ "font-size:75%",
846
+ "font-size:80%",
847
+ "font-size:inherit",
848
+ "font-variation-settings:inherit",
849
+ "font-weight:bolder",
850
+ "font-weight:inherit",
851
+ "height:0",
852
+ "height:auto",
853
+ "letter-spacing:inherit",
854
+ "line-height:1",
855
+ "line-height:1.5",
856
+ "line-height:0",
857
+ "line-height:inherit",
858
+ "list-style:none",
859
+ "margin-inline-end:4px",
860
+ "max-width:100%",
861
+ "min-height:1lh",
862
+ "opacity:1",
863
+ "outline:auto",
864
+ "padding:0",
865
+ "padding-block:0",
866
+ "position:relative",
867
+ "resize:vertical",
868
+ "tab-size:4",
869
+ "text-align:inherit",
870
+ "text-decoration:inherit",
871
+ "text-decoration:underline dotted",
872
+ "text-indent:0",
873
+ "text-transform:none",
874
+ "top:-.5em",
875
+ "vertical-align:baseline",
876
+ "vertical-align:middle"
877
+ ]);
878
+ function hasVueScopedAttr(value) {
879
+ VUE_SCOPED_ATTR_RE.lastIndex = 0;
880
+ VUE_SCOPED_CLASS_RE.lastIndex = 0;
881
+ const matched = VUE_SCOPED_ATTR_RE.test(value) || VUE_SCOPED_CLASS_RE.test(value);
882
+ VUE_SCOPED_ATTR_RE.lastIndex = 0;
883
+ VUE_SCOPED_CLASS_RE.lastIndex = 0;
884
+ return matched;
885
+ }
886
+ function normalizeCssSignatureValue(value) {
887
+ return value.replace(VUE_SCOPED_ATTR_RE, "").replace(VUE_SCOPED_CLASS_RE, "").replace(/\s+/g, " ").replace(/\s*([>+~])\s*/g, "$1").replace(/\(\s+/g, "(").replace(/\s+\)/g, ")").trim();
888
+ }
889
+ function isSfcStyleRequestSource(source) {
890
+ if (typeof source !== "string") return false;
891
+ const queryIndex = source.indexOf("?");
892
+ if (queryIndex < 0 || !source.slice(0, queryIndex).toLowerCase().endsWith(".uvue")) return false;
893
+ const hashIndex = source.indexOf("#", queryIndex);
894
+ const query = source.slice(queryIndex + 1, hashIndex < 0 ? void 0 : hashIndex);
895
+ return new URLSearchParams(query).get("type") === "style";
896
+ }
897
+ function isUvueSfcStyleRequest(result) {
898
+ if (isSfcStyleRequestSource(result.opts.from)) return true;
899
+ if ((result.root.nodes ?? []).some((node) => isSfcStyleRequestSource(node.source?.input.from))) return true;
900
+ let hasScopedSelector = false;
901
+ result.root.walkRules((rule) => {
902
+ if ((rule.selectors ?? [rule.selector]).some(hasVueScopedAttr)) {
903
+ hasScopedSelector = true;
904
+ return false;
905
+ }
906
+ });
907
+ return hasScopedSelector;
908
+ }
909
+ function getDeclarations(rule) {
910
+ return rule.nodes?.filter((node) => node.type === "decl") ?? [];
911
+ }
912
+ function isLikelyTailwindGlobalSelector(selector) {
913
+ const normalized = normalizeCssSignatureValue(selector);
914
+ return normalized === "*" || normalized.startsWith("::") || normalized.startsWith(":root") || normalized.startsWith(":host") || /^(?:html|body|hr|abbr|h1|h2|h3|h4|h5|h6|a|b|strong|code|kbd|samp|pre|small|sub|sup|table|button|input|select|optgroup|textarea|summary|blockquote|dl|dd|fieldset|legend|ol|ul|menu|dialog|progress|video|audio|canvas|embed|iframe|img|object|svg|details|template|[uo]ni-progress)(?:$|[:,[\s>+~.#])/.test(normalized);
915
+ }
916
+ function isTailwindPreflightDeclaration(decl) {
917
+ const prop = decl.prop.trim().toLowerCase();
918
+ const value = normalizeCssSignatureValue(decl.value.trim().toLowerCase());
919
+ if (prop.startsWith("--tw-")) return true;
920
+ if (prop === "color" && value.startsWith("color-mix(") && value.includes("currentcolor") && value.includes("transparent")) return true;
921
+ if (prop === "color" && value === "currentcolor") return true;
922
+ if (prop === "font-family" && value.startsWith("var(--default-font-family") || prop === "font-feature-settings" && value.startsWith("var(--default-font-feature-settings") || prop === "font-variation-settings" && value.startsWith("var(--default-font-variation-settings")) return true;
923
+ return TAILWIND_PREFLIGHT_DECLARATIONS.has(`${prop}:${value}`);
924
+ }
925
+ function isScopedTailwindThemeCarrierRule(rule) {
926
+ const selectors = rule.selectors ?? [rule.selector];
927
+ const declarations = getDeclarations(rule);
928
+ return selectors.length > 0 && selectors.every((selector) => {
929
+ const normalized = normalizeCssSignatureValue(selector);
930
+ return hasVueScopedAttr(selector) && (normalized.startsWith(":root") || normalized.startsWith(":host"));
931
+ }) && declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--"));
932
+ }
933
+ function isScopedUniversalTailwindPreflightRule(rule) {
934
+ const selectors = rule.selectors ?? [rule.selector];
935
+ const declarations = getDeclarations(rule);
936
+ return selectors.length > 0 && selectors.every((selector) => hasVueScopedAttr(selector) && SCOPED_UNIVERSAL_PREFLIGHT_SELECTORS.has(normalizeCssSignatureValue(selector))) && declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--tw-") || [
937
+ "box-sizing",
938
+ "margin",
939
+ "padding",
940
+ "border"
941
+ ].includes(decl.prop));
942
+ }
943
+ function isScopedTailwindElementPreflightRule(rule, hasTailwindBanner) {
944
+ if (!hasTailwindBanner) return false;
945
+ const selectors = rule.selectors ?? [rule.selector];
946
+ const declarations = getDeclarations(rule);
947
+ return selectors.length > 0 && selectors.every((selector) => hasVueScopedAttr(selector) && isLikelyTailwindGlobalSelector(selector)) && declarations.length > 0 && declarations.every(isTailwindPreflightDeclaration);
948
+ }
949
+ function isUnscopedMiniProgramTailwindPreflightRule(rule) {
950
+ const selectors = rule.selectors ?? [rule.selector];
951
+ if (selectors.length === 0 || !selectors.every((selector) => {
952
+ const normalized = normalizeCssSignatureValue(selector);
953
+ return !hasVueScopedAttr(selector) && MINI_PROGRAM_PREFLIGHT_SELECTORS$1.has(normalized);
954
+ })) return false;
955
+ const declarations = getDeclarations(rule);
956
+ return declarations.length > 0 && declarations.every((decl) => decl.prop.startsWith("--tw-") || [
957
+ "box-sizing",
958
+ "margin",
959
+ "padding",
960
+ "border"
961
+ ].includes(decl.prop));
962
+ }
963
+ function isScopedMiniProgramTailwindContentInitRule(rule) {
964
+ const selectors = rule.selectors ?? [rule.selector];
965
+ if (selectors.length === 0 || !selectors.every((selector) => {
966
+ const normalized = normalizeCssSignatureValue(selector);
967
+ return hasVueScopedAttr(selector) && MINI_PROGRAM_PREFLIGHT_SELECTORS$1.has(normalized);
968
+ })) return false;
969
+ const declarations = getDeclarations(rule);
970
+ return declarations.length > 0 && declarations.every((decl) => decl.prop === "--tw-content");
971
+ }
972
+ function isLikelyTailwindPropertyAtRule(atRule) {
973
+ return typeof atRule.name === "string" && atRule.name.toLowerCase() === "property" && normalizeCssSignatureValue(atRule.params).startsWith("--tw-");
974
+ }
975
+ function stripScopedTailwindNoise(root) {
976
+ let hasTailwindBanner = false;
977
+ root.walkComments((comment) => {
978
+ if (TAILWIND_VERSION_COMMENT_RE.test(comment.text)) hasTailwindBanner = true;
979
+ });
980
+ root.walkComments((comment) => {
981
+ if (TAILWIND_VERSION_COMMENT_RE.test(comment.text)) comment.remove();
982
+ });
983
+ root.walkRules((rule) => {
984
+ if (isScopedTailwindThemeCarrierRule(rule) || isScopedUniversalTailwindPreflightRule(rule) || isScopedTailwindElementPreflightRule(rule, hasTailwindBanner) || isUnscopedMiniProgramTailwindPreflightRule(rule) || isScopedMiniProgramTailwindContentInitRule(rule)) rule.remove();
985
+ });
986
+ root.walkAtRules((atRule) => {
987
+ if (isLikelyTailwindPropertyAtRule(atRule)) {
988
+ atRule.remove();
989
+ return;
990
+ }
991
+ if ((atRule.nodes?.length ?? 0) === 0) atRule.remove();
992
+ });
993
+ }
994
+ //#endregion
804
995
  //#region src/compat/uni-app-x-uvue/theme.ts
805
996
  const SYSTEM_ROOT_SELECTORS = /* @__PURE__ */ new Set([
806
997
  ":host",
@@ -998,6 +1189,7 @@ function applyUniAppXUvueCompatibility(result, options) {
998
1189
  if (!isUniAppXUvueTarget(options)) return result;
999
1190
  const mode = normalizeUnsupportedMode(options?.uniAppXUnsupported);
1000
1191
  const warningCache = /* @__PURE__ */ new Set();
1192
+ const sfcStyleRequest = options?.isMainChunk !== true && isUvueSfcStyleRequest(result);
1001
1193
  let root = result.root;
1002
1194
  let calcMessages = [];
1003
1195
  consumeUniAppXSystemRootTheme(root, options?.customPropertyValues);
@@ -1010,8 +1202,9 @@ function applyUniAppXUvueCompatibility(result, options) {
1010
1202
  root = calcResult.root;
1011
1203
  calcMessages = calcResult.messages;
1012
1204
  }
1205
+ if (sfcStyleRequest) stripScopedTailwindNoise(root);
1013
1206
  root.walkRules((rule) => {
1014
- if (!hasOnlyClassSelectors(rule)) {
1207
+ if (!sfcStyleRequest && !hasOnlyClassSelectors(rule)) {
1015
1208
  reportUnsupportedRule(rule, result, mode, warningCache, "selector must be class-only");
1016
1209
  rule.remove();
1017
1210
  return;
@@ -4260,6 +4453,81 @@ function rewriteLocalCssImportRequestsForOutput(css, options = {}) {
4260
4453
  }
4261
4454
  }
4262
4455
  //#endregion
4456
+ //#region src/compat/line-comments.ts
4457
+ /**
4458
+ * 将常见预处理器风格的行注释转换为 PostCSS 可解析的块注释。
4459
+ * 避免改写字符串、块注释和未加引号的 URL。
4460
+ */
4461
+ function normalizeCssLineComments(source) {
4462
+ if (!source.includes("//")) return source;
4463
+ const parts = [];
4464
+ let lastWriteIndex = 0;
4465
+ const syntaxCharacter = /[/"'(]/g;
4466
+ for (let match = syntaxCharacter.exec(source); match; match = syntaxCharacter.exec(source)) {
4467
+ const index = match.index;
4468
+ const char = match[0];
4469
+ const next = source[index + 1];
4470
+ if (char === "/" && next === "*" && !isEscaped(source, index)) {
4471
+ const commentEnd = source.indexOf("*/", index + 2);
4472
+ syntaxCharacter.lastIndex = commentEnd === -1 ? source.length : commentEnd + 2;
4473
+ continue;
4474
+ }
4475
+ if ((char === "\"" || char === "'") && !isEscaped(source, index)) {
4476
+ const quoteEnd = findUnescapedCharacter(source, char, index + 1);
4477
+ syntaxCharacter.lastIndex = quoteEnd === -1 ? source.length : quoteEnd + 1;
4478
+ continue;
4479
+ }
4480
+ if (char === "(" && isUrlFunctionStart(source, index)) {
4481
+ let valueStart = index + 1;
4482
+ while (valueStart < source.length && /\s/.test(source[valueStart] ?? "")) valueStart++;
4483
+ const valueStartChar = source[valueStart];
4484
+ if (valueStartChar !== "\"" && valueStartChar !== "'") {
4485
+ const urlEnd = findUnescapedCharacter(source, ")", valueStart);
4486
+ syntaxCharacter.lastIndex = urlEnd === -1 ? source.length : urlEnd + 1;
4487
+ }
4488
+ continue;
4489
+ }
4490
+ if (char === "/" && next === "/" && !isEscaped(source, index)) {
4491
+ let lineStart = index - 1;
4492
+ while (lineStart >= 0 && source[lineStart] !== "\n" && source[lineStart] !== "\r") lineStart--;
4493
+ const linePrefix = source.slice(lineStart + 1, index);
4494
+ const trimmedLinePrefix = linePrefix.trimEnd();
4495
+ const needsSemicolon = trimmedLinePrefix.length > 0 && !/[;{}]$/.test(trimmedLinePrefix);
4496
+ let unchangedPrefix = source.slice(lastWriteIndex, index);
4497
+ if (needsSemicolon) {
4498
+ const trailingWhitespaceLength = linePrefix.length - trimmedLinePrefix.length;
4499
+ const insertionIndex = unchangedPrefix.length - trailingWhitespaceLength;
4500
+ unchangedPrefix = `${unchangedPrefix.slice(0, insertionIndex)};${unchangedPrefix.slice(insertionIndex)}`;
4501
+ }
4502
+ let lineEnd = index + 2;
4503
+ while (lineEnd < source.length && source[lineEnd] !== "\n" && source[lineEnd] !== "\r") lineEnd++;
4504
+ parts.push(unchangedPrefix, "/*", source.slice(index + 2, lineEnd), "*/");
4505
+ lastWriteIndex = lineEnd;
4506
+ syntaxCharacter.lastIndex = lineEnd;
4507
+ continue;
4508
+ }
4509
+ }
4510
+ if (parts.length === 0) return source;
4511
+ parts.push(source.slice(lastWriteIndex));
4512
+ return parts.join("");
4513
+ }
4514
+ function isEscaped(source, index) {
4515
+ let backslashCount = 0;
4516
+ for (let cursor = index - 1; cursor >= 0 && source[cursor] === "\\"; cursor--) backslashCount++;
4517
+ return backslashCount % 2 === 1;
4518
+ }
4519
+ function findUnescapedCharacter(source, character, fromIndex) {
4520
+ let index = source.indexOf(character, fromIndex);
4521
+ while (index !== -1 && isEscaped(source, index)) index = source.indexOf(character, index + 1);
4522
+ return index;
4523
+ }
4524
+ function isUrlFunctionStart(source, index) {
4525
+ if (isEscaped(source, index) || index < 3) return false;
4526
+ const prefix = source.slice(index - 3, index);
4527
+ const beforePrefix = source[index - 4];
4528
+ return prefix.toLowerCase() === "url" && (beforePrefix === void 0 || !/\w/.test(beforePrefix));
4529
+ }
4530
+ //#endregion
4263
4531
  //#region src/content-probe.ts
4264
4532
  /**
4265
4533
  * 所有标志均为 false 的空信号
@@ -6444,14 +6712,15 @@ function createStyleHandler(options) {
6444
6712
  }
6445
6713
  function processSource(rawSource, root, cloneOutput, opt) {
6446
6714
  const resolvedOptions = resolver.resolve(opt);
6715
+ const normalizedRawSource = normalizeCssLineComments(rawSource);
6447
6716
  const isUniAppXFramework = resolvedOptions.appType === "uni-app-x";
6448
- const protectedVarFallbacks = resolvedOptions.uniAppX || isUniAppXFramework ? protectDynamicVarFallbacks(rawSource) : {
6449
- css: rawSource,
6717
+ const protectedVarFallbacks = resolvedOptions.uniAppX || isUniAppXFramework ? protectDynamicVarFallbacks(normalizedRawSource) : {
6718
+ css: normalizedRawSource,
6450
6719
  restore: (value) => value
6451
6720
  };
6452
6721
  const protectedColorMix = resolvedOptions.majorVersion === 4 ? protectDynamicColorMixAlpha(protectedVarFallbacks.css) : void 0;
6453
6722
  const source = protectedColorMix?.css ?? protectedVarFallbacks.css;
6454
- const processInput = source !== rawSource ? source : root?.clone() ?? source;
6723
+ const processInput = source !== normalizedRawSource ? source : root?.clone() ?? source;
6455
6724
  let signal;
6456
6725
  if (!hasUserPlugins) try {
6457
6726
  signal = probeFeatures(source);
@@ -6478,7 +6747,7 @@ function createStyleHandler(options) {
6478
6747
  finalResult = nextResult;
6479
6748
  }
6480
6749
  }
6481
- if (protectedColorMix || protectedVarFallbacks.css !== rawSource) {
6750
+ if (protectedColorMix || protectedVarFallbacks.css !== normalizedRawSource) {
6482
6751
  const restoredCss = protectedVarFallbacks.restore(protectedColorMix?.restore(finalResult.css) ?? finalResult.css);
6483
6752
  if (restoredCss !== finalResult.css) {
6484
6753
  const nextResult = finalResult.root.clone().toResult(finalResult.opts);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@weapp-tailwindcss/postcss",
3
3
  "type": "module",
4
- "version": "3.2.3",
4
+ "version": "3.2.4",
5
5
  "description": "@weapp-tailwindcss/postcss",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -83,8 +83,8 @@
83
83
  "postcss-selector-parser": "~7.1.4",
84
84
  "postcss-value-parser": "^4.2.0",
85
85
  "@weapp-tailwindcss/postcss-calc": "^1.0.3",
86
- "@weapp-tailwindcss/shared": "2.0.1",
87
- "tailwindcss-config": "2.0.2"
86
+ "tailwindcss-config": "2.0.2",
87
+ "@weapp-tailwindcss/shared": "2.0.1"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@csstools/postcss-is-pseudo-class": "^6.0.0",