tailwindcss-patch 9.4.3 → 9.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.
- package/dist/{cli-BztQHMRp.js → cli-CGyUnvFc.js} +3 -2
- package/dist/{cli-D0jXMGXf.mjs → cli-DRfALTSo.mjs} +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/commands/cli-runtime.d.mts +1 -1
- package/dist/commands/cli-runtime.d.ts +1 -1
- package/dist/commands/cli-runtime.js +2 -2
- package/dist/commands/cli-runtime.mjs +2 -2
- package/dist/{dist-DDcbvOwe.js → dist-DlC5vuI2.js} +1 -1
- package/dist/index.d.mts +7 -149
- package/dist/index.d.ts +8 -150
- package/dist/index.js +294 -521
- package/dist/index.mjs +6 -471
- package/dist/{validate-BuqRodYI.d.ts → validate-B5-08lrU.d.ts} +7 -251
- package/dist/{validate-oAkURzUC.d.mts → validate-CgrG4aAY.d.mts} +7 -251
- package/dist/{validate-Bug_WYcU.mjs → validate-Q00Ccqht.mjs} +8 -1405
- package/dist/{validate-DbuKewV-.js → validate-XiYmTZcd.js} +82 -1708
- package/package.json +8 -10
- package/src/api/tailwindcss-patcher.ts +8 -5
- package/src/extraction/candidate-extractor.ts +17 -701
- package/src/extraction/split-candidate-tokens.ts +5 -101
- package/src/options/types.ts +1 -2
- package/src/style-candidates.ts +5 -35
- package/src/style-generator.ts +11 -80
- package/src/types.ts +21 -95
- package/src/v3/index.ts +2 -2
- package/src/v4/index.ts +104 -28
- package/src/v3/style-generator.ts +0 -384
- package/src/v4/bare-arbitrary-values.ts +0 -545
- package/src/v4/candidates.ts +0 -316
- package/src/v4/engine.ts +0 -112
- package/src/v4/node-adapter.ts +0 -207
- package/src/v4/source-scan.ts +0 -432
- package/src/v4/source.ts +0 -235
- package/src/v4/style-generator.ts +0 -44
- package/src/v4/types.ts +0 -103
|
@@ -8,17 +8,15 @@ import { createHash } from "node:crypto";
|
|
|
8
8
|
import { createConsola } from "consola";
|
|
9
9
|
import path$1 from "node:path";
|
|
10
10
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
|
-
import {
|
|
12
|
-
import postcss from "postcss";
|
|
13
|
-
import { stat } from "node:fs/promises";
|
|
14
|
-
import micromatch from "micromatch";
|
|
11
|
+
import { extractProjectCandidatesWithPositions, extractRawCandidates, extractRawCandidatesWithPositions, extractSourceCandidates, extractSourceCandidatesWithPositions, extractValidCandidates, groupTokensByFile, resolveProjectSourceFiles } from "@tailwindcss-mangle/engine";
|
|
15
12
|
import * as t from "@babel/types";
|
|
16
13
|
import generate from "@babel/generator";
|
|
17
14
|
import _babelTraverse from "@babel/traverse";
|
|
18
15
|
import { parse, parse as parse$1 } from "@babel/parser";
|
|
16
|
+
import postcss from "postcss";
|
|
19
17
|
import { loadConfig } from "tailwindcss-config";
|
|
20
18
|
//#region package.json
|
|
21
|
-
var version = "9.
|
|
19
|
+
var version = "9.5.0";
|
|
22
20
|
//#endregion
|
|
23
21
|
//#region src/constants.ts
|
|
24
22
|
const pkgName = "tailwindcss-patch";
|
|
@@ -1412,7 +1410,7 @@ function normalizeOptions(options = {}) {
|
|
|
1412
1410
|
};
|
|
1413
1411
|
}
|
|
1414
1412
|
//#endregion
|
|
1415
|
-
//#region ../../node_modules/.pnpm/tsdown@0.22.
|
|
1413
|
+
//#region ../../node_modules/.pnpm/tsdown@0.22.3_tsx@4.22.4_typescript@6.0.3_unrun@0.2.37_synckit@0.11.13_/node_modules/tsdown/esm-shims.js
|
|
1416
1414
|
const getFilename = () => fileURLToPath(import.meta.url);
|
|
1417
1415
|
const getDirname = () => path$1.dirname(getFilename());
|
|
1418
1416
|
const __dirname = /* @__PURE__ */ getDirname();
|
|
@@ -1458,1401 +1456,6 @@ async function loadPatchOptionsForWorkspace(cwd, overrides) {
|
|
|
1458
1456
|
return merge(overrides ?? {}, base, { projectRoot: cwd });
|
|
1459
1457
|
}
|
|
1460
1458
|
//#endregion
|
|
1461
|
-
//#region src/v4/bare-arbitrary-values.ts
|
|
1462
|
-
const DEFAULT_BARE_ARBITRARY_VALUE_UNITS = [
|
|
1463
|
-
"%",
|
|
1464
|
-
"px",
|
|
1465
|
-
"rpx",
|
|
1466
|
-
"rem",
|
|
1467
|
-
"em",
|
|
1468
|
-
"vw",
|
|
1469
|
-
"vh",
|
|
1470
|
-
"vmin",
|
|
1471
|
-
"vmax",
|
|
1472
|
-
"dvw",
|
|
1473
|
-
"dvh",
|
|
1474
|
-
"svw",
|
|
1475
|
-
"svh",
|
|
1476
|
-
"lvw",
|
|
1477
|
-
"lvh",
|
|
1478
|
-
"ch",
|
|
1479
|
-
"ex",
|
|
1480
|
-
"lh",
|
|
1481
|
-
"rlh",
|
|
1482
|
-
"fr",
|
|
1483
|
-
"deg",
|
|
1484
|
-
"rad",
|
|
1485
|
-
"turn",
|
|
1486
|
-
"s",
|
|
1487
|
-
"ms"
|
|
1488
|
-
];
|
|
1489
|
-
const NUMBER_RE = /^-?(?:\d+|\d*\.\d+)$/;
|
|
1490
|
-
const FUNCTION_VALUE_RE = /^[a-z_-][\w-]*\(/i;
|
|
1491
|
-
const HEX_ESCAPE_RE = /^[\da-f]$/i;
|
|
1492
|
-
const ASPECT_RATIO_RE = /^\d+\/\d+$/;
|
|
1493
|
-
const ESCAPED_WHITESPACE_RE = /\\[nrt]/g;
|
|
1494
|
-
function splitVariantPrefix(candidate) {
|
|
1495
|
-
let depth = 0;
|
|
1496
|
-
let quote;
|
|
1497
|
-
let lastSeparator = -1;
|
|
1498
|
-
for (let index = 0; index < candidate.length; index++) {
|
|
1499
|
-
const character = candidate[index];
|
|
1500
|
-
if (character === "\\") {
|
|
1501
|
-
index++;
|
|
1502
|
-
continue;
|
|
1503
|
-
}
|
|
1504
|
-
if (quote) {
|
|
1505
|
-
if (character === quote) quote = void 0;
|
|
1506
|
-
continue;
|
|
1507
|
-
}
|
|
1508
|
-
if (character === "\"" || character === "'") {
|
|
1509
|
-
quote = character;
|
|
1510
|
-
continue;
|
|
1511
|
-
}
|
|
1512
|
-
if (character === "[" || character === "(" || character === "{") {
|
|
1513
|
-
depth++;
|
|
1514
|
-
continue;
|
|
1515
|
-
}
|
|
1516
|
-
if (character === "]" || character === ")" || character === "}") {
|
|
1517
|
-
depth = Math.max(0, depth - 1);
|
|
1518
|
-
continue;
|
|
1519
|
-
}
|
|
1520
|
-
if (depth === 0 && character === ":") lastSeparator = index;
|
|
1521
|
-
}
|
|
1522
|
-
if (lastSeparator === -1) return {
|
|
1523
|
-
prefix: "",
|
|
1524
|
-
body: candidate
|
|
1525
|
-
};
|
|
1526
|
-
return {
|
|
1527
|
-
prefix: candidate.slice(0, lastSeparator + 1),
|
|
1528
|
-
body: candidate.slice(lastSeparator + 1)
|
|
1529
|
-
};
|
|
1530
|
-
}
|
|
1531
|
-
function isBalancedFunctionValue(value) {
|
|
1532
|
-
let depth = 0;
|
|
1533
|
-
let quote;
|
|
1534
|
-
for (let index = 0; index < value.length; index++) {
|
|
1535
|
-
const character = value[index];
|
|
1536
|
-
if (character === "\\") {
|
|
1537
|
-
index++;
|
|
1538
|
-
continue;
|
|
1539
|
-
}
|
|
1540
|
-
if (quote) {
|
|
1541
|
-
if (character === quote) quote = void 0;
|
|
1542
|
-
continue;
|
|
1543
|
-
}
|
|
1544
|
-
if (character === "\"" || character === "'") {
|
|
1545
|
-
quote = character;
|
|
1546
|
-
continue;
|
|
1547
|
-
}
|
|
1548
|
-
if (character === "(") {
|
|
1549
|
-
depth++;
|
|
1550
|
-
continue;
|
|
1551
|
-
}
|
|
1552
|
-
if (character === ")") {
|
|
1553
|
-
depth--;
|
|
1554
|
-
if (depth < 0) return false;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
return depth === 0 && quote === void 0;
|
|
1558
|
-
}
|
|
1559
|
-
function isEscapedAt(value, index) {
|
|
1560
|
-
let slashCount = 0;
|
|
1561
|
-
for (let slashIndex = index - 1; slashIndex >= 0 && value[slashIndex] === "\\"; slashIndex--) slashCount++;
|
|
1562
|
-
return slashCount % 2 === 1;
|
|
1563
|
-
}
|
|
1564
|
-
function isBalancedBareArbitraryBody(value) {
|
|
1565
|
-
let depth = 0;
|
|
1566
|
-
let quote;
|
|
1567
|
-
for (let index = 0; index < value.length; index++) {
|
|
1568
|
-
const character = value[index];
|
|
1569
|
-
if (isEscapedAt(value, index)) continue;
|
|
1570
|
-
if (quote) {
|
|
1571
|
-
if (character === quote) quote = void 0;
|
|
1572
|
-
continue;
|
|
1573
|
-
}
|
|
1574
|
-
if (character === "\"" || character === "'") {
|
|
1575
|
-
quote = character;
|
|
1576
|
-
continue;
|
|
1577
|
-
}
|
|
1578
|
-
if (character === "(" || character === "{") {
|
|
1579
|
-
depth++;
|
|
1580
|
-
continue;
|
|
1581
|
-
}
|
|
1582
|
-
if (character === ")" || character === "}") {
|
|
1583
|
-
depth--;
|
|
1584
|
-
if (depth < 0) return false;
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
return depth === 0 && quote === void 0;
|
|
1588
|
-
}
|
|
1589
|
-
function isHexColorValue(value) {
|
|
1590
|
-
return /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6,8})$/i.test(value);
|
|
1591
|
-
}
|
|
1592
|
-
function isQuotedValue(value) {
|
|
1593
|
-
const quote = value[0];
|
|
1594
|
-
if (quote !== "\"" && quote !== "'" || value[value.length - 1] !== quote) return false;
|
|
1595
|
-
let escaped = false;
|
|
1596
|
-
for (let index = 1; index < value.length - 1; index++) {
|
|
1597
|
-
const character = value[index];
|
|
1598
|
-
if (escaped) {
|
|
1599
|
-
escaped = false;
|
|
1600
|
-
continue;
|
|
1601
|
-
}
|
|
1602
|
-
if (character === "\\") escaped = true;
|
|
1603
|
-
}
|
|
1604
|
-
return !escaped;
|
|
1605
|
-
}
|
|
1606
|
-
function normalizeBareArbitraryValueOptions(options) {
|
|
1607
|
-
if (options === false || options === void 0 || options === null) return;
|
|
1608
|
-
const units = options === true ? DEFAULT_BARE_ARBITRARY_VALUE_UNITS : options.units ?? DEFAULT_BARE_ARBITRARY_VALUE_UNITS;
|
|
1609
|
-
const normalizedUnits = [...new Set(units.filter((unit) => typeof unit === "string" && unit.length > 0))];
|
|
1610
|
-
if (normalizedUnits.length === 0) return;
|
|
1611
|
-
return { units: normalizedUnits.sort((a, b) => b.length - a.length) };
|
|
1612
|
-
}
|
|
1613
|
-
function isBareArbitraryValuesEnabled(options) {
|
|
1614
|
-
return normalizeBareArbitraryValueOptions(options) !== void 0;
|
|
1615
|
-
}
|
|
1616
|
-
function normalizeEscapedValue(value) {
|
|
1617
|
-
let result = "";
|
|
1618
|
-
for (let index = 0; index < value.length; index++) {
|
|
1619
|
-
const character = value[index];
|
|
1620
|
-
if (character !== "\\") {
|
|
1621
|
-
result += character;
|
|
1622
|
-
continue;
|
|
1623
|
-
}
|
|
1624
|
-
const nextCharacter = value[index + 1];
|
|
1625
|
-
if (nextCharacter === void 0) {
|
|
1626
|
-
result += character;
|
|
1627
|
-
continue;
|
|
1628
|
-
}
|
|
1629
|
-
if (HEX_ESCAPE_RE.test(nextCharacter)) {
|
|
1630
|
-
let hex = "";
|
|
1631
|
-
let nextIndex = index + 1;
|
|
1632
|
-
while (nextIndex < value.length && hex.length < 6) {
|
|
1633
|
-
const hexCharacter = value[nextIndex];
|
|
1634
|
-
if (hexCharacter === void 0 || !HEX_ESCAPE_RE.test(hexCharacter)) break;
|
|
1635
|
-
hex += hexCharacter;
|
|
1636
|
-
nextIndex++;
|
|
1637
|
-
}
|
|
1638
|
-
if (/[\t\n\f\r ]/.test(value[nextIndex] ?? "")) nextIndex++;
|
|
1639
|
-
const decoded = String.fromCodePoint(Number.parseInt(hex, 16));
|
|
1640
|
-
result += decoded === "_" ? "\\_" : decoded;
|
|
1641
|
-
index = nextIndex - 1;
|
|
1642
|
-
continue;
|
|
1643
|
-
}
|
|
1644
|
-
result += nextCharacter === "_" ? "\\_" : nextCharacter;
|
|
1645
|
-
index++;
|
|
1646
|
-
}
|
|
1647
|
-
return result;
|
|
1648
|
-
}
|
|
1649
|
-
function resolveValueWithUnit(body, units) {
|
|
1650
|
-
const value = normalizeEscapedValue(body);
|
|
1651
|
-
for (const unit of units) {
|
|
1652
|
-
if (!value.endsWith(unit)) continue;
|
|
1653
|
-
const numberPart = value.slice(0, -unit.length);
|
|
1654
|
-
if (NUMBER_RE.test(numberPart)) return `${numberPart}${unit}`;
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
function resolveArbitraryValue(utility, body, units) {
|
|
1658
|
-
const value = normalizeEscapedValue(body);
|
|
1659
|
-
const withUnit = resolveValueWithUnit(value, units);
|
|
1660
|
-
if (withUnit) return withUnit;
|
|
1661
|
-
if (utility === "aspect" && ASPECT_RATIO_RE.test(value)) return value;
|
|
1662
|
-
if (isHexColorValue(value)) return value;
|
|
1663
|
-
if (isQuotedValue(value)) return value;
|
|
1664
|
-
if (FUNCTION_VALUE_RE.test(value) && value.endsWith(")") && isBalancedFunctionValue(value)) {
|
|
1665
|
-
if (utility === "text" && /^var\(/i.test(value)) return `color:${value}`;
|
|
1666
|
-
return value;
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
function resolveUtilityAndValue(body, units) {
|
|
1670
|
-
let depth = 0;
|
|
1671
|
-
let quote;
|
|
1672
|
-
for (let index = body.length - 1; index > 0; index--) {
|
|
1673
|
-
const character = body[index];
|
|
1674
|
-
if (isEscapedAt(body, index)) continue;
|
|
1675
|
-
if (quote) {
|
|
1676
|
-
if (character === quote) quote = void 0;
|
|
1677
|
-
continue;
|
|
1678
|
-
}
|
|
1679
|
-
if (character === "\"" || character === "'") {
|
|
1680
|
-
quote = character;
|
|
1681
|
-
continue;
|
|
1682
|
-
}
|
|
1683
|
-
if (character === ")" || character === "}") {
|
|
1684
|
-
depth++;
|
|
1685
|
-
continue;
|
|
1686
|
-
}
|
|
1687
|
-
if (character === "(" || character === "{") {
|
|
1688
|
-
depth = Math.max(0, depth - 1);
|
|
1689
|
-
continue;
|
|
1690
|
-
}
|
|
1691
|
-
if (depth > 0 || character !== "-") continue;
|
|
1692
|
-
const utility = body.slice(0, index);
|
|
1693
|
-
const rawValue = body.slice(index + 1);
|
|
1694
|
-
if (!utility || !rawValue) continue;
|
|
1695
|
-
const value = resolveArbitraryValue(utility, rawValue, units);
|
|
1696
|
-
if (value) return {
|
|
1697
|
-
utility,
|
|
1698
|
-
value
|
|
1699
|
-
};
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
function resolveBareArbitraryValueCandidate(candidate, options) {
|
|
1703
|
-
const normalizedOptions = normalizeBareArbitraryValueOptions(options);
|
|
1704
|
-
if (!normalizedOptions || !candidate || candidate.includes("[") || candidate.includes("]")) return;
|
|
1705
|
-
const { prefix, body } = splitVariantPrefix(candidate);
|
|
1706
|
-
const important = body.startsWith("!") ? "!" : "";
|
|
1707
|
-
let normalizedBody = important ? body.slice(1) : body;
|
|
1708
|
-
const negative = normalizedBody.startsWith("-") ? "-" : "";
|
|
1709
|
-
if (negative) normalizedBody = normalizedBody.slice(1);
|
|
1710
|
-
if (!isBalancedBareArbitraryBody(normalizedBody)) return;
|
|
1711
|
-
const resolved = resolveUtilityAndValue(normalizedBody, normalizedOptions.units);
|
|
1712
|
-
if (!resolved) return;
|
|
1713
|
-
return {
|
|
1714
|
-
candidate,
|
|
1715
|
-
canonicalCandidate: `${prefix}${important}${negative}${resolved.utility}-[${resolved.value}]`
|
|
1716
|
-
};
|
|
1717
|
-
}
|
|
1718
|
-
function isBareArbitrarySourceSplitter(char) {
|
|
1719
|
-
return /\s/.test(char);
|
|
1720
|
-
}
|
|
1721
|
-
function isQuoteBoundary(content, start, index) {
|
|
1722
|
-
const tokenPrefix = content.slice(start, index);
|
|
1723
|
-
return tokenPrefix.length === 0 || !tokenPrefix.endsWith("-");
|
|
1724
|
-
}
|
|
1725
|
-
function trimBareArbitrarySourceToken(token, start) {
|
|
1726
|
-
let nextToken = token;
|
|
1727
|
-
let nextStart = start;
|
|
1728
|
-
while (nextToken.length > 0 && /^[<{([]$/.test(nextToken[0])) {
|
|
1729
|
-
nextToken = nextToken.slice(1);
|
|
1730
|
-
nextStart++;
|
|
1731
|
-
}
|
|
1732
|
-
while (nextToken.length > 0 && /^[>\],;]$/.test(nextToken[nextToken.length - 1])) nextToken = nextToken.slice(0, -1);
|
|
1733
|
-
return {
|
|
1734
|
-
token: nextToken,
|
|
1735
|
-
start: nextStart
|
|
1736
|
-
};
|
|
1737
|
-
}
|
|
1738
|
-
function pushBareArbitrarySourceCandidate(result, token, start, options) {
|
|
1739
|
-
const trimmed = trimBareArbitrarySourceToken(token, start);
|
|
1740
|
-
if (!trimmed.token || trimmed.token.includes("=") || trimmed.token.includes("[") || trimmed.token.includes("]")) return;
|
|
1741
|
-
if (!resolveBareArbitraryValueCandidate(trimmed.token, options)) return;
|
|
1742
|
-
result.push({
|
|
1743
|
-
rawCandidate: trimmed.token,
|
|
1744
|
-
start: trimmed.start,
|
|
1745
|
-
end: trimmed.start + trimmed.token.length
|
|
1746
|
-
});
|
|
1747
|
-
}
|
|
1748
|
-
function extractBareArbitraryValueSourceCandidatesWithPositions(content, options) {
|
|
1749
|
-
if (!isBareArbitraryValuesEnabled(options)) return [];
|
|
1750
|
-
const normalized = content.includes("\\") ? content.replace(ESCAPED_WHITESPACE_RE, " ") : content;
|
|
1751
|
-
const result = [];
|
|
1752
|
-
let depth = 0;
|
|
1753
|
-
let quote;
|
|
1754
|
-
let start = 0;
|
|
1755
|
-
for (let index = 0; index < normalized.length; index++) {
|
|
1756
|
-
const char = normalized[index];
|
|
1757
|
-
if (char === void 0) continue;
|
|
1758
|
-
if (char === "\\") {
|
|
1759
|
-
index++;
|
|
1760
|
-
continue;
|
|
1761
|
-
}
|
|
1762
|
-
if (quote) {
|
|
1763
|
-
if (char === quote) quote = void 0;
|
|
1764
|
-
} else if ((char === "\"" || char === "'" || char === "`") && !isQuoteBoundary(normalized, start, index)) quote = char;
|
|
1765
|
-
else if (char === "(" || char === "{" || char === "[") depth++;
|
|
1766
|
-
else if (char === ")" || char === "}" || char === "]") depth = Math.max(0, depth - 1);
|
|
1767
|
-
if (!isBareArbitrarySourceSplitter(char) && !((char === "\"" || char === "'" || char === "`") && depth === 0 && isQuoteBoundary(normalized, start, index))) continue;
|
|
1768
|
-
pushBareArbitrarySourceCandidate(result, normalized.slice(start, index), start, options);
|
|
1769
|
-
start = index + 1;
|
|
1770
|
-
}
|
|
1771
|
-
pushBareArbitrarySourceCandidate(result, normalized.slice(start), start, options);
|
|
1772
|
-
return result;
|
|
1773
|
-
}
|
|
1774
|
-
function extractBareArbitraryValueSourceCandidates(content, options) {
|
|
1775
|
-
return [...new Set(extractBareArbitraryValueSourceCandidatesWithPositions(content, options).map((candidate) => candidate.rawCandidate))];
|
|
1776
|
-
}
|
|
1777
|
-
function escapeCssClassName(value) {
|
|
1778
|
-
let result = "";
|
|
1779
|
-
for (let index = 0; index < value.length; index++) {
|
|
1780
|
-
const codeUnit = value.charCodeAt(index);
|
|
1781
|
-
const character = value.charAt(index);
|
|
1782
|
-
if (codeUnit === 0) {
|
|
1783
|
-
result += "�";
|
|
1784
|
-
continue;
|
|
1785
|
-
}
|
|
1786
|
-
if (codeUnit >= 1 && codeUnit <= 31 || codeUnit === 127 || index === 0 && codeUnit >= 48 && codeUnit <= 57 || index === 1 && codeUnit >= 48 && codeUnit <= 57 && value.charCodeAt(0) === 45) {
|
|
1787
|
-
result += `\\${codeUnit.toString(16)} `;
|
|
1788
|
-
continue;
|
|
1789
|
-
}
|
|
1790
|
-
if (codeUnit >= 128 || codeUnit === 45 || codeUnit === 95 || codeUnit >= 48 && codeUnit <= 57 || codeUnit >= 65 && codeUnit <= 90 || codeUnit >= 97 && codeUnit <= 122) {
|
|
1791
|
-
result += character;
|
|
1792
|
-
continue;
|
|
1793
|
-
}
|
|
1794
|
-
result += `\\${character}`;
|
|
1795
|
-
}
|
|
1796
|
-
return result;
|
|
1797
|
-
}
|
|
1798
|
-
//#endregion
|
|
1799
|
-
//#region src/v4/candidates.ts
|
|
1800
|
-
function resolveValidTailwindV4Candidates(designSystem, candidates, options) {
|
|
1801
|
-
const validCandidates = /* @__PURE__ */ new Set();
|
|
1802
|
-
const parsedCandidates = [];
|
|
1803
|
-
const originalCandidatesByCanonical = /* @__PURE__ */ new Map();
|
|
1804
|
-
for (const candidate of candidates) {
|
|
1805
|
-
if (!candidate) continue;
|
|
1806
|
-
const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options?.bareArbitraryValues);
|
|
1807
|
-
const candidateToCheck = bareArbitrary?.canonicalCandidate ?? candidate;
|
|
1808
|
-
if (bareArbitrary) {
|
|
1809
|
-
const originalCandidates = originalCandidatesByCanonical.get(candidateToCheck) ?? /* @__PURE__ */ new Set();
|
|
1810
|
-
originalCandidates.add(candidate);
|
|
1811
|
-
originalCandidatesByCanonical.set(candidateToCheck, originalCandidates);
|
|
1812
|
-
}
|
|
1813
|
-
if (parsedCandidates.includes(candidateToCheck)) continue;
|
|
1814
|
-
if (designSystem.parseCandidate(candidateToCheck).length > 0) parsedCandidates.push(candidateToCheck);
|
|
1815
|
-
}
|
|
1816
|
-
if (parsedCandidates.length === 0) return validCandidates;
|
|
1817
|
-
const cssByCandidate = designSystem.candidatesToCss(parsedCandidates);
|
|
1818
|
-
for (let index = 0; index < parsedCandidates.length; index++) {
|
|
1819
|
-
const candidate = parsedCandidates[index];
|
|
1820
|
-
const candidateCss = cssByCandidate[index];
|
|
1821
|
-
if (candidate && typeof candidateCss === "string" && candidateCss.trim().length > 0) {
|
|
1822
|
-
const originalCandidates = originalCandidatesByCanonical.get(candidate);
|
|
1823
|
-
if (originalCandidates) {
|
|
1824
|
-
for (const originalCandidate of originalCandidates) validCandidates.add(originalCandidate);
|
|
1825
|
-
continue;
|
|
1826
|
-
}
|
|
1827
|
-
validCandidates.add(candidate);
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
return validCandidates;
|
|
1831
|
-
}
|
|
1832
|
-
function createSelectorAliasMap(candidates, options) {
|
|
1833
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
1834
|
-
for (const candidate of candidates) {
|
|
1835
|
-
const bareArbitrary = resolveBareArbitraryValueCandidate(candidate, options);
|
|
1836
|
-
if (!bareArbitrary) continue;
|
|
1837
|
-
const canonicalSelector = escapeCssClassName(bareArbitrary.canonicalCandidate);
|
|
1838
|
-
const bareSelectors = aliases.get(canonicalSelector) ?? /* @__PURE__ */ new Set();
|
|
1839
|
-
bareSelectors.add(escapeCssClassName(bareArbitrary.candidate));
|
|
1840
|
-
aliases.set(canonicalSelector, bareSelectors);
|
|
1841
|
-
}
|
|
1842
|
-
return aliases;
|
|
1843
|
-
}
|
|
1844
|
-
function replaceBareArbitraryValueSelectors(css, candidates, options) {
|
|
1845
|
-
const aliases = createSelectorAliasMap(candidates, options);
|
|
1846
|
-
if (aliases.size === 0) return css;
|
|
1847
|
-
if (Array.from(aliases.values()).every((bareSelectors) => bareSelectors.size === 1)) {
|
|
1848
|
-
let result = css;
|
|
1849
|
-
for (const [canonicalSelector, bareSelectors] of aliases) {
|
|
1850
|
-
const bareSelector = Array.from(bareSelectors)[0];
|
|
1851
|
-
if (bareSelector !== void 0) result = result.replaceAll(canonicalSelector, bareSelector);
|
|
1852
|
-
}
|
|
1853
|
-
return result;
|
|
1854
|
-
}
|
|
1855
|
-
const root = postcss.parse(css);
|
|
1856
|
-
root.walkRules((rule) => {
|
|
1857
|
-
let selectors = rule.selectors;
|
|
1858
|
-
for (const [canonicalSelector, bareSelectors] of aliases) selectors = selectors.flatMap((selector) => {
|
|
1859
|
-
if (!selector.includes(canonicalSelector)) return selector;
|
|
1860
|
-
return Array.from(bareSelectors, (bareSelector) => selector.replaceAll(canonicalSelector, bareSelector));
|
|
1861
|
-
});
|
|
1862
|
-
rule.selectors = selectors;
|
|
1863
|
-
});
|
|
1864
|
-
return root.toString();
|
|
1865
|
-
}
|
|
1866
|
-
function canonicalizeBareArbitraryValueCandidates(candidates, options) {
|
|
1867
|
-
return Array.from(candidates, (candidate) => {
|
|
1868
|
-
return resolveBareArbitraryValueCandidate(candidate, options)?.canonicalCandidate ?? candidate;
|
|
1869
|
-
});
|
|
1870
|
-
}
|
|
1871
|
-
function splitTopLevel(value, separator, options) {
|
|
1872
|
-
const result = [];
|
|
1873
|
-
let start = 0;
|
|
1874
|
-
let depth = 0;
|
|
1875
|
-
let quote;
|
|
1876
|
-
for (let index = 0; index < value.length; index++) {
|
|
1877
|
-
const character = value[index];
|
|
1878
|
-
if (character === "\\") {
|
|
1879
|
-
index++;
|
|
1880
|
-
continue;
|
|
1881
|
-
}
|
|
1882
|
-
if (quote) {
|
|
1883
|
-
if (character === quote) quote = void 0;
|
|
1884
|
-
continue;
|
|
1885
|
-
}
|
|
1886
|
-
if (character === "\"" || character === "'") {
|
|
1887
|
-
quote = character;
|
|
1888
|
-
continue;
|
|
1889
|
-
}
|
|
1890
|
-
if (character === "(" || character === "[" || character === "{") {
|
|
1891
|
-
depth++;
|
|
1892
|
-
continue;
|
|
1893
|
-
}
|
|
1894
|
-
if (character === ")" || character === "]" || character === "}") {
|
|
1895
|
-
depth = Math.max(0, depth - 1);
|
|
1896
|
-
continue;
|
|
1897
|
-
}
|
|
1898
|
-
if (depth === 0 && character === separator) {
|
|
1899
|
-
const item = value.slice(start, index).trim();
|
|
1900
|
-
if (item || options?.keepEmpty) result.push(item);
|
|
1901
|
-
start = index + 1;
|
|
1902
|
-
}
|
|
1903
|
-
}
|
|
1904
|
-
const item = value.slice(start).trim();
|
|
1905
|
-
if (item || options?.keepEmpty) result.push(item);
|
|
1906
|
-
return result;
|
|
1907
|
-
}
|
|
1908
|
-
const sequencePattern = /^(-?\d+)\.\.(-?\d+)(?:\.\.(-?\d+))?$/;
|
|
1909
|
-
function expandSequence(value) {
|
|
1910
|
-
const match = value.match(sequencePattern);
|
|
1911
|
-
if (!match) return [value];
|
|
1912
|
-
const [, startValue, endValue, stepValue] = match;
|
|
1913
|
-
if (startValue === void 0 || endValue === void 0) return [value];
|
|
1914
|
-
const start = Number.parseInt(startValue, 10);
|
|
1915
|
-
const end = Number.parseInt(endValue, 10);
|
|
1916
|
-
let step = stepValue === void 0 ? start <= end ? 1 : -1 : Number.parseInt(stepValue, 10);
|
|
1917
|
-
if (step === 0) throw new Error("Step cannot be zero in Tailwind CSS v4 inline source sequence.");
|
|
1918
|
-
const ascending = start < end;
|
|
1919
|
-
if (ascending && step < 0) step = -step;
|
|
1920
|
-
if (!ascending && step > 0) step = -step;
|
|
1921
|
-
const result = [];
|
|
1922
|
-
for (let current = start; ascending ? current <= end : current >= end; current += step) result.push(current.toString());
|
|
1923
|
-
return result;
|
|
1924
|
-
}
|
|
1925
|
-
function expandInlinePattern(pattern) {
|
|
1926
|
-
const openIndex = pattern.indexOf("{");
|
|
1927
|
-
if (openIndex === -1) return [pattern];
|
|
1928
|
-
const prefix = pattern.slice(0, openIndex);
|
|
1929
|
-
const rest = pattern.slice(openIndex);
|
|
1930
|
-
let depth = 0;
|
|
1931
|
-
let closeIndex = -1;
|
|
1932
|
-
for (let index = 0; index < rest.length; index++) {
|
|
1933
|
-
const character = rest[index];
|
|
1934
|
-
if (character === "{") depth++;
|
|
1935
|
-
else if (character === "}") {
|
|
1936
|
-
depth--;
|
|
1937
|
-
if (depth === 0) {
|
|
1938
|
-
closeIndex = index;
|
|
1939
|
-
break;
|
|
1940
|
-
}
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
if (closeIndex === -1) throw new Error(`The Tailwind CSS v4 inline source pattern "${pattern}" is not balanced.`);
|
|
1944
|
-
const body = rest.slice(1, closeIndex);
|
|
1945
|
-
const suffix = rest.slice(closeIndex + 1);
|
|
1946
|
-
const parts = sequencePattern.test(body) ? expandSequence(body) : splitTopLevel(body, ",", { keepEmpty: true }).flatMap((part) => expandInlinePattern(part));
|
|
1947
|
-
const suffixes = expandInlinePattern(suffix);
|
|
1948
|
-
const result = [];
|
|
1949
|
-
for (const part of parts) for (const expandedSuffix of suffixes) result.push(`${prefix}${part}${expandedSuffix}`);
|
|
1950
|
-
return result;
|
|
1951
|
-
}
|
|
1952
|
-
function unquoteCssString(value) {
|
|
1953
|
-
const quote = value[0];
|
|
1954
|
-
if (quote !== "\"" && quote !== "'" || value[value.length - 1] !== quote) return;
|
|
1955
|
-
let result = "";
|
|
1956
|
-
for (let index = 1; index < value.length - 1; index++) {
|
|
1957
|
-
const character = value[index];
|
|
1958
|
-
if (character === "\\") {
|
|
1959
|
-
index++;
|
|
1960
|
-
result += value[index] ?? "";
|
|
1961
|
-
continue;
|
|
1962
|
-
}
|
|
1963
|
-
result += character;
|
|
1964
|
-
}
|
|
1965
|
-
return result;
|
|
1966
|
-
}
|
|
1967
|
-
function extractTailwindV4InlineSourceCandidates(css) {
|
|
1968
|
-
const included = /* @__PURE__ */ new Set();
|
|
1969
|
-
const excluded = /* @__PURE__ */ new Set();
|
|
1970
|
-
postcss.parse(css).walkAtRules("source", (rule) => {
|
|
1971
|
-
let params = rule.params.trim();
|
|
1972
|
-
if (!params) return;
|
|
1973
|
-
let negated = false;
|
|
1974
|
-
if (params.startsWith("not ")) {
|
|
1975
|
-
negated = true;
|
|
1976
|
-
params = params.slice(4).trim();
|
|
1977
|
-
}
|
|
1978
|
-
if (!params.startsWith("inline(") || !params.endsWith(")")) return;
|
|
1979
|
-
const inlineValue = unquoteCssString(params.slice(7, -1).trim());
|
|
1980
|
-
if (inlineValue === void 0) return;
|
|
1981
|
-
const target = negated ? excluded : included;
|
|
1982
|
-
for (const part of splitTopLevel(inlineValue, " ")) for (const candidate of expandInlinePattern(part)) target.add(candidate);
|
|
1983
|
-
});
|
|
1984
|
-
return {
|
|
1985
|
-
included,
|
|
1986
|
-
excluded
|
|
1987
|
-
};
|
|
1988
|
-
}
|
|
1989
|
-
//#endregion
|
|
1990
|
-
//#region src/v4/node-adapter.ts
|
|
1991
|
-
const nodeModulePromiseCache = /* @__PURE__ */ new Map();
|
|
1992
|
-
const designSystemPromiseCache = /* @__PURE__ */ new Map();
|
|
1993
|
-
function unique(values) {
|
|
1994
|
-
return Array.from(new Set(Array.from(values).filter(Boolean).map((value) => path.resolve(value))));
|
|
1995
|
-
}
|
|
1996
|
-
function createRequireBase(base) {
|
|
1997
|
-
return path.join(base, "package.json");
|
|
1998
|
-
}
|
|
1999
|
-
function isRelativeSpecifier(id) {
|
|
2000
|
-
return id.startsWith("./") || id.startsWith("../") || id === "." || id === "..";
|
|
2001
|
-
}
|
|
2002
|
-
function isAbsoluteSpecifier(id) {
|
|
2003
|
-
return path.isAbsolute(id);
|
|
2004
|
-
}
|
|
2005
|
-
function isCssSpecifier(id) {
|
|
2006
|
-
return path.extname(id) === ".css";
|
|
2007
|
-
}
|
|
2008
|
-
function createCssResolutionCandidates(id) {
|
|
2009
|
-
if (isCssSpecifier(id)) return [id];
|
|
2010
|
-
return [`${id}/index.css`, id];
|
|
2011
|
-
}
|
|
2012
|
-
function createFallbackCssResolver(baseCandidates) {
|
|
2013
|
-
const bases = unique(baseCandidates);
|
|
2014
|
-
return async (id) => {
|
|
2015
|
-
if (isRelativeSpecifier(id) || isAbsoluteSpecifier(id)) return;
|
|
2016
|
-
for (const base of bases) {
|
|
2017
|
-
const requireFromBase = createRequire(createRequireBase(base));
|
|
2018
|
-
for (const candidate of createCssResolutionCandidates(id)) try {
|
|
2019
|
-
return requireFromBase.resolve(candidate);
|
|
2020
|
-
} catch {}
|
|
2021
|
-
}
|
|
2022
|
-
};
|
|
2023
|
-
}
|
|
2024
|
-
async function importResolvedModule(resolved) {
|
|
2025
|
-
return import(pathToFileURL(resolved).href);
|
|
2026
|
-
}
|
|
2027
|
-
async function importTailwindNodeFromBase(base) {
|
|
2028
|
-
try {
|
|
2029
|
-
return await importResolvedModule(createRequire(createRequireBase(base)).resolve("@tailwindcss/node"));
|
|
2030
|
-
} catch {
|
|
2031
|
-
return;
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
async function importFallbackTailwindNode() {
|
|
2035
|
-
return import("@tailwindcss/node");
|
|
2036
|
-
}
|
|
2037
|
-
async function loadTailwindV4NodeModule(baseCandidates) {
|
|
2038
|
-
const bases = unique(baseCandidates);
|
|
2039
|
-
const cacheKey = JSON.stringify(bases);
|
|
2040
|
-
const cached = nodeModulePromiseCache.get(cacheKey);
|
|
2041
|
-
if (cached) return cached;
|
|
2042
|
-
const promise = (async () => {
|
|
2043
|
-
for (const base of bases) {
|
|
2044
|
-
const loaded = await importTailwindNodeFromBase(base);
|
|
2045
|
-
if (loaded) return loaded;
|
|
2046
|
-
}
|
|
2047
|
-
return importFallbackTailwindNode();
|
|
2048
|
-
})();
|
|
2049
|
-
nodeModulePromiseCache.set(cacheKey, promise);
|
|
2050
|
-
promise.catch(() => {
|
|
2051
|
-
if (nodeModulePromiseCache.get(cacheKey) === promise) nodeModulePromiseCache.delete(cacheKey);
|
|
2052
|
-
});
|
|
2053
|
-
return promise;
|
|
2054
|
-
}
|
|
2055
|
-
function createDesignSystemCacheKey(css, bases) {
|
|
2056
|
-
return JSON.stringify({
|
|
2057
|
-
css,
|
|
2058
|
-
bases: unique(bases)
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
|
-
function getTailwindV4DesignSystemCacheKey(source) {
|
|
2062
|
-
return createDesignSystemCacheKey(source.css, [source.base, ...source.baseFallbacks]);
|
|
2063
|
-
}
|
|
2064
|
-
async function loadTailwindV4DesignSystem(source) {
|
|
2065
|
-
const bases = unique([source.base, ...source.baseFallbacks]);
|
|
2066
|
-
if (bases.length === 0) throw new Error("No base directories provided for Tailwind CSS v4 design system.");
|
|
2067
|
-
const cacheKey = createDesignSystemCacheKey(source.css, bases);
|
|
2068
|
-
const cached = designSystemPromiseCache.get(cacheKey);
|
|
2069
|
-
if (cached) return cached;
|
|
2070
|
-
const promise = (async () => {
|
|
2071
|
-
const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]);
|
|
2072
|
-
let lastError;
|
|
2073
|
-
for (const base of bases) try {
|
|
2074
|
-
return await node.__unstable__loadDesignSystem(source.css, { base });
|
|
2075
|
-
} catch (error) {
|
|
2076
|
-
lastError = error;
|
|
2077
|
-
}
|
|
2078
|
-
if (lastError instanceof Error) throw lastError;
|
|
2079
|
-
throw new Error("Failed to load Tailwind CSS v4 design system.");
|
|
2080
|
-
})();
|
|
2081
|
-
designSystemPromiseCache.set(cacheKey, promise);
|
|
2082
|
-
promise.catch(() => {
|
|
2083
|
-
if (designSystemPromiseCache.get(cacheKey) === promise) designSystemPromiseCache.delete(cacheKey);
|
|
2084
|
-
});
|
|
2085
|
-
return promise;
|
|
2086
|
-
}
|
|
2087
|
-
async function compileTailwindV4Source(source) {
|
|
2088
|
-
const bases = unique([source.base, ...source.baseFallbacks]);
|
|
2089
|
-
if (bases.length === 0) throw new Error("No base directories provided for Tailwind CSS v4 compiler.");
|
|
2090
|
-
const node = await loadTailwindV4NodeModule([source.projectRoot, ...bases]);
|
|
2091
|
-
let lastError;
|
|
2092
|
-
for (const base of bases) {
|
|
2093
|
-
const dependencies = new Set(source.dependencies);
|
|
2094
|
-
try {
|
|
2095
|
-
return {
|
|
2096
|
-
compiled: await node.compile(source.css, {
|
|
2097
|
-
base,
|
|
2098
|
-
customCssResolver: createFallbackCssResolver([source.projectRoot, ...bases]),
|
|
2099
|
-
onDependency(dependency) {
|
|
2100
|
-
dependencies.add(path.resolve(dependency));
|
|
2101
|
-
}
|
|
2102
|
-
}),
|
|
2103
|
-
dependencies
|
|
2104
|
-
};
|
|
2105
|
-
} catch (error) {
|
|
2106
|
-
lastError = error;
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
if (lastError instanceof Error) throw lastError;
|
|
2110
|
-
throw new Error("Failed to compile Tailwind CSS v4 source.");
|
|
2111
|
-
}
|
|
2112
|
-
//#endregion
|
|
2113
|
-
//#region src/v4/source-scan.ts
|
|
2114
|
-
const TAILWIND_V4_IGNORED_CONTENT_DIRS = [
|
|
2115
|
-
".git",
|
|
2116
|
-
".hg",
|
|
2117
|
-
".jj",
|
|
2118
|
-
".next",
|
|
2119
|
-
".parcel-cache",
|
|
2120
|
-
".pnpm-store",
|
|
2121
|
-
".svelte-kit",
|
|
2122
|
-
".svn",
|
|
2123
|
-
".turbo",
|
|
2124
|
-
".venv",
|
|
2125
|
-
".vercel",
|
|
2126
|
-
".yarn",
|
|
2127
|
-
"__pycache__",
|
|
2128
|
-
"node_modules",
|
|
2129
|
-
"venv"
|
|
2130
|
-
];
|
|
2131
|
-
const TAILWIND_V4_IGNORED_EXTENSIONS = [
|
|
2132
|
-
"less",
|
|
2133
|
-
"lock",
|
|
2134
|
-
"sass",
|
|
2135
|
-
"scss",
|
|
2136
|
-
"styl",
|
|
2137
|
-
"log"
|
|
2138
|
-
];
|
|
2139
|
-
const TAILWIND_V4_IGNORED_FILES = [
|
|
2140
|
-
"package-lock.json",
|
|
2141
|
-
"pnpm-lock.yaml",
|
|
2142
|
-
"bun.lockb",
|
|
2143
|
-
".gitignore",
|
|
2144
|
-
".env",
|
|
2145
|
-
".env.*"
|
|
2146
|
-
];
|
|
2147
|
-
const TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN = "**/*";
|
|
2148
|
-
function uniqueResolvedPaths(values) {
|
|
2149
|
-
const result = [];
|
|
2150
|
-
for (const value of values) {
|
|
2151
|
-
if (!value) continue;
|
|
2152
|
-
const resolved = path.resolve(value);
|
|
2153
|
-
if (!result.includes(resolved)) result.push(resolved);
|
|
2154
|
-
}
|
|
2155
|
-
return result;
|
|
2156
|
-
}
|
|
2157
|
-
function toPosixPath(value) {
|
|
2158
|
-
return value.replaceAll(path.sep, "/");
|
|
2159
|
-
}
|
|
2160
|
-
function resolveSourceScanPath(value) {
|
|
2161
|
-
const resolved = path.resolve(value);
|
|
2162
|
-
try {
|
|
2163
|
-
return realpathSync.native(resolved);
|
|
2164
|
-
} catch {
|
|
2165
|
-
return resolved;
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
function normalizeGlobPattern(pattern) {
|
|
2169
|
-
return pattern.startsWith("./") ? pattern.slice(2) : pattern;
|
|
2170
|
-
}
|
|
2171
|
-
function hasGlobMagic(value) {
|
|
2172
|
-
return /[*?[\]{}()!+@]/.test(value);
|
|
2173
|
-
}
|
|
2174
|
-
function splitStaticGlobPrefix(pattern) {
|
|
2175
|
-
const segments = normalizeGlobPattern(pattern).split(/[\\/]+/);
|
|
2176
|
-
const prefix = [];
|
|
2177
|
-
const rest = [];
|
|
2178
|
-
let reachedGlob = false;
|
|
2179
|
-
for (const segment of segments) {
|
|
2180
|
-
if (!reachedGlob && segment && !hasGlobMagic(segment)) {
|
|
2181
|
-
prefix.push(segment);
|
|
2182
|
-
continue;
|
|
2183
|
-
}
|
|
2184
|
-
reachedGlob = true;
|
|
2185
|
-
rest.push(segment);
|
|
2186
|
-
}
|
|
2187
|
-
return {
|
|
2188
|
-
prefix,
|
|
2189
|
-
rest
|
|
2190
|
-
};
|
|
2191
|
-
}
|
|
2192
|
-
async function pathExistsAsDirectory(file) {
|
|
2193
|
-
try {
|
|
2194
|
-
return (await stat(file)).isDirectory();
|
|
2195
|
-
} catch {
|
|
2196
|
-
return false;
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
function createTailwindV4DefaultIgnoreSources(base) {
|
|
2200
|
-
return [
|
|
2201
|
-
...TAILWIND_V4_IGNORED_CONTENT_DIRS.map((pattern) => ({
|
|
2202
|
-
base,
|
|
2203
|
-
pattern: `**/${pattern}/**`,
|
|
2204
|
-
negated: true
|
|
2205
|
-
})),
|
|
2206
|
-
...TAILWIND_V4_IGNORED_EXTENSIONS.map((extension) => ({
|
|
2207
|
-
base,
|
|
2208
|
-
pattern: `**/*.${extension}`,
|
|
2209
|
-
negated: true
|
|
2210
|
-
})),
|
|
2211
|
-
...TAILWIND_V4_IGNORED_FILES.map((pattern) => ({
|
|
2212
|
-
base,
|
|
2213
|
-
pattern: `**/${pattern}`,
|
|
2214
|
-
negated: true
|
|
2215
|
-
}))
|
|
2216
|
-
];
|
|
2217
|
-
}
|
|
2218
|
-
function createTailwindV4RootSources(root, fallbackBase) {
|
|
2219
|
-
if (root === "none") return [];
|
|
2220
|
-
if (root === null) return [{
|
|
2221
|
-
base: fallbackBase,
|
|
2222
|
-
pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
|
|
2223
|
-
negated: false
|
|
2224
|
-
}];
|
|
2225
|
-
return [{
|
|
2226
|
-
...root,
|
|
2227
|
-
negated: false
|
|
2228
|
-
}];
|
|
2229
|
-
}
|
|
2230
|
-
function createTailwindV4CompiledSourceEntries(root, sources, fallbackBase) {
|
|
2231
|
-
return [...createTailwindV4RootSources(root, fallbackBase), ...sources];
|
|
2232
|
-
}
|
|
2233
|
-
async function resolveTailwindV4SourceEntry(sourcePath, base, negated, defaultPattern = TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN) {
|
|
2234
|
-
const absoluteSource = path.isAbsolute(sourcePath) ? path.resolve(sourcePath) : path.resolve(base, sourcePath);
|
|
2235
|
-
if (await pathExistsAsDirectory(absoluteSource)) return {
|
|
2236
|
-
base: absoluteSource,
|
|
2237
|
-
negated,
|
|
2238
|
-
pattern: normalizeGlobPattern(defaultPattern)
|
|
2239
|
-
};
|
|
2240
|
-
if (path.isAbsolute(sourcePath)) return {
|
|
2241
|
-
base: path.dirname(absoluteSource),
|
|
2242
|
-
negated,
|
|
2243
|
-
pattern: normalizeGlobPattern(path.basename(absoluteSource))
|
|
2244
|
-
};
|
|
2245
|
-
const { prefix, rest } = splitStaticGlobPrefix(sourcePath);
|
|
2246
|
-
if (prefix.length > 0 && rest.length > 0) return {
|
|
2247
|
-
base: path.resolve(base, ...prefix),
|
|
2248
|
-
negated,
|
|
2249
|
-
pattern: normalizeGlobPattern(rest.join("/"))
|
|
2250
|
-
};
|
|
2251
|
-
return {
|
|
2252
|
-
base,
|
|
2253
|
-
negated,
|
|
2254
|
-
pattern: normalizeGlobPattern(sourcePath)
|
|
2255
|
-
};
|
|
2256
|
-
}
|
|
2257
|
-
async function normalizeTailwindV4SourceEntries(sources, options = {}) {
|
|
2258
|
-
const cwd = options.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
2259
|
-
return Promise.all(sources.map((source) => resolveTailwindV4SourceEntry(source.pattern, source.base ? path.resolve(source.base) : cwd, source.negated, options.defaultPattern)));
|
|
2260
|
-
}
|
|
2261
|
-
function expandBracePattern(pattern) {
|
|
2262
|
-
const index = pattern.indexOf("{");
|
|
2263
|
-
if (index === -1) return [pattern];
|
|
2264
|
-
const rest = pattern.slice(index);
|
|
2265
|
-
let depth = 0;
|
|
2266
|
-
let endIndex = -1;
|
|
2267
|
-
for (let i = 0; i < rest.length; i++) {
|
|
2268
|
-
const char = rest[i];
|
|
2269
|
-
if (char === "\\") {
|
|
2270
|
-
i += 1;
|
|
2271
|
-
continue;
|
|
2272
|
-
}
|
|
2273
|
-
if (char === "{") {
|
|
2274
|
-
depth += 1;
|
|
2275
|
-
continue;
|
|
2276
|
-
}
|
|
2277
|
-
if (char === "}") {
|
|
2278
|
-
depth -= 1;
|
|
2279
|
-
if (depth === 0) {
|
|
2280
|
-
endIndex = i;
|
|
2281
|
-
break;
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
if (endIndex === -1) return [pattern];
|
|
2286
|
-
const prefix = pattern.slice(0, index);
|
|
2287
|
-
const inner = rest.slice(1, endIndex);
|
|
2288
|
-
const suffix = rest.slice(endIndex + 1);
|
|
2289
|
-
const parts = [];
|
|
2290
|
-
const stack = [];
|
|
2291
|
-
let lastPos = 0;
|
|
2292
|
-
for (let i = 0; i < inner.length; i++) {
|
|
2293
|
-
const char = inner[i];
|
|
2294
|
-
if (char === "\\") {
|
|
2295
|
-
i += 1;
|
|
2296
|
-
continue;
|
|
2297
|
-
}
|
|
2298
|
-
if (char === "{") {
|
|
2299
|
-
stack.push("}");
|
|
2300
|
-
continue;
|
|
2301
|
-
}
|
|
2302
|
-
if (char === "}" && stack[stack.length - 1] === "}") {
|
|
2303
|
-
stack.pop();
|
|
2304
|
-
continue;
|
|
2305
|
-
}
|
|
2306
|
-
if (char === "," && stack.length === 0) {
|
|
2307
|
-
parts.push(inner.slice(lastPos, i));
|
|
2308
|
-
lastPos = i + 1;
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
parts.push(inner.slice(lastPos));
|
|
2312
|
-
return parts.flatMap((part) => expandBracePattern(`${prefix}${part}${suffix}`));
|
|
2313
|
-
}
|
|
2314
|
-
function expandTailwindV4SourceEntryBraces(sources) {
|
|
2315
|
-
return sources.flatMap((source) => {
|
|
2316
|
-
const base = path.resolve(source.base);
|
|
2317
|
-
return expandBracePattern(source.pattern).map((pattern) => ({
|
|
2318
|
-
base,
|
|
2319
|
-
pattern,
|
|
2320
|
-
negated: source.negated
|
|
2321
|
-
}));
|
|
2322
|
-
});
|
|
2323
|
-
}
|
|
2324
|
-
function normalizeTailwindV4ScannerSources(sources, cwd, ignoredSources = []) {
|
|
2325
|
-
return expandTailwindV4SourceEntryBraces([...sources?.length ? sources : [{
|
|
2326
|
-
base: cwd,
|
|
2327
|
-
pattern: TAILWIND_V4_AUTO_SOURCE_SCAN_PATTERN,
|
|
2328
|
-
negated: false
|
|
2329
|
-
}], ...ignoredSources]);
|
|
2330
|
-
}
|
|
2331
|
-
function normalizeEntryPattern(entry) {
|
|
2332
|
-
return path.isAbsolute(entry.pattern) ? toPosixPath(path.relative(resolveSourceScanPath(entry.base), entry.pattern)) : normalizeGlobPattern(entry.pattern);
|
|
2333
|
-
}
|
|
2334
|
-
function isFileMatchedByTailwindV4SourceEntry(file, entry) {
|
|
2335
|
-
const relative = toPosixPath(path.relative(resolveSourceScanPath(entry.base), file));
|
|
2336
|
-
return Boolean(relative) && !relative.startsWith("../") && !path.isAbsolute(relative) && micromatch.isMatch(relative, normalizeEntryPattern(entry));
|
|
2337
|
-
}
|
|
2338
|
-
function isFileExcludedByTailwindV4SourceEntries(file, entries) {
|
|
2339
|
-
if (!entries?.length) return false;
|
|
2340
|
-
const resolvedFile = resolveSourceScanPath(file);
|
|
2341
|
-
return entries.some((entry) => entry.negated && isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
|
|
2342
|
-
}
|
|
2343
|
-
function isFileMatchedByTailwindV4SourceEntries(file, entries) {
|
|
2344
|
-
if (!entries?.length) return true;
|
|
2345
|
-
const positiveEntries = entries.filter((entry) => !entry.negated);
|
|
2346
|
-
const negativeEntries = entries.filter((entry) => entry.negated);
|
|
2347
|
-
if (positiveEntries.length === 0) return false;
|
|
2348
|
-
const resolvedFile = resolveSourceScanPath(file);
|
|
2349
|
-
if (!positiveEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry))) return false;
|
|
2350
|
-
return !negativeEntries.some((entry) => isFileMatchedByTailwindV4SourceEntry(resolvedFile, entry));
|
|
2351
|
-
}
|
|
2352
|
-
function createTailwindV4SourceEntryMatcher(entries) {
|
|
2353
|
-
if (!entries?.length) return;
|
|
2354
|
-
return (file) => isFileMatchedByTailwindV4SourceEntries(file, entries);
|
|
2355
|
-
}
|
|
2356
|
-
function createTailwindV4SourceExclusionMatcher(entries) {
|
|
2357
|
-
if (!entries?.length) return;
|
|
2358
|
-
return (file) => isFileExcludedByTailwindV4SourceEntries(file, entries);
|
|
2359
|
-
}
|
|
2360
|
-
function groupTailwindV4SourceEntriesByBase(entries) {
|
|
2361
|
-
const entriesByBase = /* @__PURE__ */ new Map();
|
|
2362
|
-
for (const entry of entries) {
|
|
2363
|
-
const base = path.resolve(entry.base);
|
|
2364
|
-
const group = entriesByBase.get(base) ?? [];
|
|
2365
|
-
group.push({
|
|
2366
|
-
...entry,
|
|
2367
|
-
base,
|
|
2368
|
-
pattern: normalizeGlobPattern(entry.pattern)
|
|
2369
|
-
});
|
|
2370
|
-
entriesByBase.set(base, group);
|
|
2371
|
-
}
|
|
2372
|
-
return entriesByBase;
|
|
2373
|
-
}
|
|
2374
|
-
async function expandTailwindV4SourceEntries(entries, resolveFiles) {
|
|
2375
|
-
if (entries.length === 0) return [];
|
|
2376
|
-
const files = /* @__PURE__ */ new Set();
|
|
2377
|
-
await Promise.all([...groupTailwindV4SourceEntriesByBase(entries).entries()].map(async ([base, group]) => {
|
|
2378
|
-
const matched = await resolveFiles({
|
|
2379
|
-
cwd: base,
|
|
2380
|
-
sources: group
|
|
2381
|
-
});
|
|
2382
|
-
for (const file of matched) files.add(path.resolve(file));
|
|
2383
|
-
}));
|
|
2384
|
-
return [...files].filter((file) => !isFileExcludedByTailwindV4SourceEntries(file, entries));
|
|
2385
|
-
}
|
|
2386
|
-
function mergeTailwindV4SourceEntries(...entries) {
|
|
2387
|
-
const result = [];
|
|
2388
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2389
|
-
for (const group of entries) for (const entry of group ?? []) {
|
|
2390
|
-
const normalized = {
|
|
2391
|
-
base: path.resolve(entry.base),
|
|
2392
|
-
pattern: normalizeGlobPattern(entry.pattern),
|
|
2393
|
-
negated: entry.negated
|
|
2394
|
-
};
|
|
2395
|
-
const key = JSON.stringify(normalized);
|
|
2396
|
-
if (seen.has(key)) continue;
|
|
2397
|
-
seen.add(key);
|
|
2398
|
-
result.push(normalized);
|
|
2399
|
-
}
|
|
2400
|
-
return result;
|
|
2401
|
-
}
|
|
2402
|
-
function resolveTailwindV4SourceBaseCandidates(projectRoot, base, baseFallbacks) {
|
|
2403
|
-
return uniqueResolvedPaths([
|
|
2404
|
-
base,
|
|
2405
|
-
projectRoot,
|
|
2406
|
-
...baseFallbacks
|
|
2407
|
-
]);
|
|
2408
|
-
}
|
|
2409
|
-
//#endregion
|
|
2410
|
-
//#region src/extraction/candidate-extractor.ts
|
|
2411
|
-
let oxideImportPromise;
|
|
2412
|
-
const designSystemCandidateCache = /* @__PURE__ */ new Map();
|
|
2413
|
-
function createOxideRuntimeDependencyError(cause) {
|
|
2414
|
-
return new Error([
|
|
2415
|
-
"tailwindcss-patch could not load @tailwindcss/oxide, which is required for source candidate scanning.",
|
|
2416
|
-
"This dependency should be installed automatically by tailwindcss-patch.",
|
|
2417
|
-
"Reinstall dependencies without disabling optional dependencies, or install @tailwindcss/oxide@^4.2.4 manually if your package manager omitted it."
|
|
2418
|
-
].join(" "), { cause });
|
|
2419
|
-
}
|
|
2420
|
-
async function importOxide() {
|
|
2421
|
-
try {
|
|
2422
|
-
return await import("@tailwindcss/oxide");
|
|
2423
|
-
} catch (error) {
|
|
2424
|
-
throw createOxideRuntimeDependencyError(error);
|
|
2425
|
-
}
|
|
2426
|
-
}
|
|
2427
|
-
function getOxideModule() {
|
|
2428
|
-
oxideImportPromise ??= importOxide();
|
|
2429
|
-
oxideImportPromise.catch(() => {
|
|
2430
|
-
oxideImportPromise = void 0;
|
|
2431
|
-
});
|
|
2432
|
-
return oxideImportPromise;
|
|
2433
|
-
}
|
|
2434
|
-
const HTML_ATTRIBUTE_NAME_CANDIDATE_RE = /^(?:class|className|hover-class|hoverClass)$/;
|
|
2435
|
-
const CSS_DIRECTIVE_CANDIDATE_RE = /^@(?:apply|tailwind|source|config|plugin|theme|utility|custom-variant|variant)$/;
|
|
2436
|
-
const CSS_APPLY_IMPORTANT = "!important";
|
|
2437
|
-
const CSS_APPLY_RE = /@apply\s+([^;{}]+)/g;
|
|
2438
|
-
const JS_LIKE_SOURCE_EXTENSION_RE = /^[cm]?[jt]sx?$/;
|
|
2439
|
-
const MIXED_TEMPLATE_SOURCE_EXTENSION_RE = /^(?:vue|uvue|nvue|svelte|mpx)$/;
|
|
2440
|
-
const CSS_LIKE_SOURCE_EXTENSION_RE = /^(?:css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|styl|stylus)$/;
|
|
2441
|
-
const SFC_SCRIPT_BLOCK_RE = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
|
|
2442
|
-
function isWhitespace(value) {
|
|
2443
|
-
return value === " " || value === "\n" || value === "\r" || value === " " || value === "\f";
|
|
2444
|
-
}
|
|
2445
|
-
function isHtmlAttributeNameCandidate(content, candidate) {
|
|
2446
|
-
if (!HTML_ATTRIBUTE_NAME_CANDIDATE_RE.test(candidate.rawCandidate)) return false;
|
|
2447
|
-
let index = candidate.end;
|
|
2448
|
-
while (isWhitespace(content[index])) index++;
|
|
2449
|
-
return content[index] === "=";
|
|
2450
|
-
}
|
|
2451
|
-
function isInsideHtmlTagText(content, candidate) {
|
|
2452
|
-
if (content.lastIndexOf("<", candidate.start) > content.lastIndexOf(">", candidate.start)) return false;
|
|
2453
|
-
const nextOpen = content.indexOf("<", candidate.end);
|
|
2454
|
-
return nextOpen !== -1 && (nextOpen < content.indexOf(">", candidate.end) || !content.includes(">", candidate.end));
|
|
2455
|
-
}
|
|
2456
|
-
function isCssDirectiveCandidate(candidate) {
|
|
2457
|
-
return candidate === CSS_APPLY_IMPORTANT || CSS_DIRECTIVE_CANDIDATE_RE.test(candidate);
|
|
2458
|
-
}
|
|
2459
|
-
function isCandidateInCssApplyParams(content, candidate) {
|
|
2460
|
-
const apply = content.lastIndexOf("@apply", candidate.start);
|
|
2461
|
-
if (apply === -1) return false;
|
|
2462
|
-
const boundary = content.slice(apply + 6, candidate.start);
|
|
2463
|
-
return !/[;{}]/.test(boundary);
|
|
2464
|
-
}
|
|
2465
|
-
function isCandidateInsideJsStringStaticContent(content, start) {
|
|
2466
|
-
let quote;
|
|
2467
|
-
let templateExpressionDepth = 0;
|
|
2468
|
-
for (let index = 0; index < start; index++) {
|
|
2469
|
-
const char = content[index];
|
|
2470
|
-
const next = content[index + 1];
|
|
2471
|
-
if (quote && char === "\\") {
|
|
2472
|
-
index++;
|
|
2473
|
-
continue;
|
|
2474
|
-
}
|
|
2475
|
-
if (quote === "`" && templateExpressionDepth > 0) {
|
|
2476
|
-
if (char === "\"" || char === "'") {
|
|
2477
|
-
const nestedQuote = char;
|
|
2478
|
-
index++;
|
|
2479
|
-
while (index < start) {
|
|
2480
|
-
const nestedChar = content[index];
|
|
2481
|
-
if (nestedChar === "\\") {
|
|
2482
|
-
index += 2;
|
|
2483
|
-
continue;
|
|
2484
|
-
}
|
|
2485
|
-
if (nestedChar === nestedQuote) break;
|
|
2486
|
-
index++;
|
|
2487
|
-
}
|
|
2488
|
-
continue;
|
|
2489
|
-
}
|
|
2490
|
-
if (char === "`") {
|
|
2491
|
-
index++;
|
|
2492
|
-
while (index < start) {
|
|
2493
|
-
const nestedChar = content[index];
|
|
2494
|
-
if (nestedChar === "\\") {
|
|
2495
|
-
index += 2;
|
|
2496
|
-
continue;
|
|
2497
|
-
}
|
|
2498
|
-
if (nestedChar === "`") break;
|
|
2499
|
-
index++;
|
|
2500
|
-
}
|
|
2501
|
-
continue;
|
|
2502
|
-
}
|
|
2503
|
-
if (char === "{") {
|
|
2504
|
-
templateExpressionDepth++;
|
|
2505
|
-
continue;
|
|
2506
|
-
}
|
|
2507
|
-
if (char === "}") {
|
|
2508
|
-
templateExpressionDepth--;
|
|
2509
|
-
continue;
|
|
2510
|
-
}
|
|
2511
|
-
continue;
|
|
2512
|
-
}
|
|
2513
|
-
if (quote) {
|
|
2514
|
-
if (quote === "`" && char === "$" && next === "{") {
|
|
2515
|
-
templateExpressionDepth = 1;
|
|
2516
|
-
index++;
|
|
2517
|
-
continue;
|
|
2518
|
-
}
|
|
2519
|
-
if (char === quote) quote = void 0;
|
|
2520
|
-
continue;
|
|
2521
|
-
}
|
|
2522
|
-
if (char === "\"" || char === "'" || char === "`") quote = char;
|
|
2523
|
-
}
|
|
2524
|
-
return quote !== void 0 && templateExpressionDepth === 0;
|
|
2525
|
-
}
|
|
2526
|
-
function shouldKeepSourceCandidate(content, extension, candidate) {
|
|
2527
|
-
if (!candidate.rawCandidate || isCssDirectiveCandidate(candidate.rawCandidate)) return false;
|
|
2528
|
-
if (CSS_LIKE_SOURCE_EXTENSION_RE.test(extension) && !isCandidateInCssApplyParams(content, candidate)) return false;
|
|
2529
|
-
if (isHtmlAttributeNameCandidate(content, candidate)) return false;
|
|
2530
|
-
if (isInsideHtmlTagText(content, candidate)) return false;
|
|
2531
|
-
if (JS_LIKE_SOURCE_EXTENSION_RE.test(extension) && !isCandidateInsideJsStringStaticContent(content, candidate.start)) return false;
|
|
2532
|
-
return true;
|
|
2533
|
-
}
|
|
2534
|
-
function createLocalCandidate(candidate) {
|
|
2535
|
-
return {
|
|
2536
|
-
rawCandidate: candidate.rawCandidate,
|
|
2537
|
-
start: candidate.localStart,
|
|
2538
|
-
end: candidate.localStart + candidate.rawCandidate.length
|
|
2539
|
-
};
|
|
2540
|
-
}
|
|
2541
|
-
function dedupeCandidatesWithPositions(candidates) {
|
|
2542
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2543
|
-
return candidates.filter((candidate) => {
|
|
2544
|
-
const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}`;
|
|
2545
|
-
if (seen.has(key)) return false;
|
|
2546
|
-
seen.add(key);
|
|
2547
|
-
return true;
|
|
2548
|
-
});
|
|
2549
|
-
}
|
|
2550
|
-
function createBareArbitraryValueCandidateContexts(content, extension, offset, options) {
|
|
2551
|
-
return extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues).map((candidate) => ({
|
|
2552
|
-
content,
|
|
2553
|
-
extension,
|
|
2554
|
-
localStart: candidate.start,
|
|
2555
|
-
rawCandidate: candidate.rawCandidate,
|
|
2556
|
-
start: candidate.start + offset,
|
|
2557
|
-
end: candidate.end + offset
|
|
2558
|
-
}));
|
|
2559
|
-
}
|
|
2560
|
-
async function extractCssApplyCandidates(content, extension, options) {
|
|
2561
|
-
const candidates = [];
|
|
2562
|
-
CSS_APPLY_RE.lastIndex = 0;
|
|
2563
|
-
let match = CSS_APPLY_RE.exec(content);
|
|
2564
|
-
while (match !== null) {
|
|
2565
|
-
const applyParams = match[1] ?? "";
|
|
2566
|
-
const applyParamsStart = match.index + match[0].indexOf(applyParams);
|
|
2567
|
-
const applyCandidates = await extractRawCandidatesWithPositions(applyParams, extension);
|
|
2568
|
-
candidates.push(...applyCandidates.map((candidate) => ({
|
|
2569
|
-
content: applyParams,
|
|
2570
|
-
extension: "html",
|
|
2571
|
-
localStart: candidate.start,
|
|
2572
|
-
rawCandidate: candidate.rawCandidate,
|
|
2573
|
-
start: candidate.start + applyParamsStart,
|
|
2574
|
-
end: candidate.end + applyParamsStart
|
|
2575
|
-
})));
|
|
2576
|
-
candidates.push(...createBareArbitraryValueCandidateContexts(applyParams, "html", applyParamsStart, options));
|
|
2577
|
-
match = CSS_APPLY_RE.exec(content);
|
|
2578
|
-
}
|
|
2579
|
-
return candidates;
|
|
2580
|
-
}
|
|
2581
|
-
async function extractMixedSourceScriptCandidates(content, options) {
|
|
2582
|
-
const candidates = [];
|
|
2583
|
-
SFC_SCRIPT_BLOCK_RE.lastIndex = 0;
|
|
2584
|
-
let match = SFC_SCRIPT_BLOCK_RE.exec(content);
|
|
2585
|
-
while (match !== null) {
|
|
2586
|
-
const scriptContent = match[1] ?? "";
|
|
2587
|
-
const scriptStart = match.index + match[0].indexOf(scriptContent);
|
|
2588
|
-
const scriptCandidates = await extractRawCandidatesWithPositions(scriptContent, "js");
|
|
2589
|
-
candidates.push(...scriptCandidates.map((candidate) => ({
|
|
2590
|
-
content: scriptContent,
|
|
2591
|
-
extension: "js",
|
|
2592
|
-
localStart: candidate.start,
|
|
2593
|
-
rawCandidate: candidate.rawCandidate,
|
|
2594
|
-
start: candidate.start + scriptStart,
|
|
2595
|
-
end: candidate.end + scriptStart
|
|
2596
|
-
})));
|
|
2597
|
-
candidates.push(...createBareArbitraryValueCandidateContexts(scriptContent, "js", scriptStart, options));
|
|
2598
|
-
match = SFC_SCRIPT_BLOCK_RE.exec(content);
|
|
2599
|
-
}
|
|
2600
|
-
return candidates;
|
|
2601
|
-
}
|
|
2602
|
-
function createCandidateCacheKey(designSystemKey, options) {
|
|
2603
|
-
if (options.bareArbitraryValues == null || options.bareArbitraryValues === false) return designSystemKey;
|
|
2604
|
-
return `${designSystemKey}:bare-arbitrary:${JSON.stringify(options.bareArbitraryValues)}`;
|
|
2605
|
-
}
|
|
2606
|
-
async function extractRawCandidatesWithPositions(content, extension = "html", options) {
|
|
2607
|
-
const { Scanner } = await getOxideModule();
|
|
2608
|
-
const candidates = new Scanner({}).getCandidatesWithPositions({
|
|
2609
|
-
content,
|
|
2610
|
-
extension
|
|
2611
|
-
}).map(({ candidate, position }) => ({
|
|
2612
|
-
rawCandidate: candidate,
|
|
2613
|
-
start: position,
|
|
2614
|
-
end: position + candidate.length
|
|
2615
|
-
}));
|
|
2616
|
-
candidates.push(...extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues));
|
|
2617
|
-
return dedupeCandidatesWithPositions(candidates);
|
|
2618
|
-
}
|
|
2619
|
-
async function extractSourceCandidatesWithPositions(content, extension = "html", options) {
|
|
2620
|
-
const normalizedExtension = extension.replace(/^\./, "");
|
|
2621
|
-
const candidates = CSS_LIKE_SOURCE_EXTENSION_RE.test(normalizedExtension) ? await extractCssApplyCandidates(content, normalizedExtension, options) : (await extractRawCandidatesWithPositions(content, normalizedExtension, options)).map((candidate) => ({
|
|
2622
|
-
...candidate,
|
|
2623
|
-
content,
|
|
2624
|
-
extension: normalizedExtension,
|
|
2625
|
-
localStart: candidate.start
|
|
2626
|
-
}));
|
|
2627
|
-
if (MIXED_TEMPLATE_SOURCE_EXTENSION_RE.test(normalizedExtension)) candidates.push(...await extractMixedSourceScriptCandidates(content, options));
|
|
2628
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2629
|
-
return candidates.filter((candidate) => {
|
|
2630
|
-
if (!shouldKeepSourceCandidate(candidate.content, candidate.extension, createLocalCandidate(candidate))) return false;
|
|
2631
|
-
const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}`;
|
|
2632
|
-
if (seen.has(key)) return false;
|
|
2633
|
-
seen.add(key);
|
|
2634
|
-
return true;
|
|
2635
|
-
}).map(({ rawCandidate, start, end }) => ({
|
|
2636
|
-
rawCandidate,
|
|
2637
|
-
start,
|
|
2638
|
-
end
|
|
2639
|
-
}));
|
|
2640
|
-
}
|
|
2641
|
-
async function extractSourceCandidates(content, extension = "html", options) {
|
|
2642
|
-
const candidates = await extractSourceCandidatesWithPositions(content, extension, options);
|
|
2643
|
-
return [...new Set(candidates.map((candidate) => candidate.rawCandidate))];
|
|
2644
|
-
}
|
|
2645
|
-
async function extractRawCandidates(sources, options) {
|
|
2646
|
-
const { Scanner } = await getOxideModule();
|
|
2647
|
-
const scanner = new Scanner(sources === void 0 ? {} : { sources });
|
|
2648
|
-
const candidates = new Set(scanner.scan());
|
|
2649
|
-
if (options?.bareArbitraryValues !== void 0 && options.bareArbitraryValues !== false) await Promise.all((scanner.files ?? []).map(async (file) => {
|
|
2650
|
-
try {
|
|
2651
|
-
const content = await promises.readFile(file, "utf8");
|
|
2652
|
-
const extension = toExtension(file);
|
|
2653
|
-
for (const candidate of extractBareArbitraryValueSourceCandidatesWithPositions(content, options.bareArbitraryValues)) if (shouldKeepSourceCandidate(content, extension, candidate)) candidates.add(candidate.rawCandidate);
|
|
2654
|
-
} catch {}
|
|
2655
|
-
}));
|
|
2656
|
-
return [...candidates];
|
|
2657
|
-
}
|
|
2658
|
-
async function extractValidCandidates(options) {
|
|
2659
|
-
const providedOptions = options ?? {};
|
|
2660
|
-
const defaultCwd = providedOptions.cwd ?? process.cwd();
|
|
2661
|
-
const base = providedOptions.base ?? defaultCwd;
|
|
2662
|
-
const baseFallbacks = providedOptions.baseFallbacks ?? [];
|
|
2663
|
-
const css = providedOptions.css ?? "@import \"tailwindcss\";";
|
|
2664
|
-
const sources = (providedOptions.sources ?? [{
|
|
2665
|
-
base: defaultCwd,
|
|
2666
|
-
pattern: "**/*",
|
|
2667
|
-
negated: false
|
|
2668
|
-
}]).map((source) => ({
|
|
2669
|
-
base: source.base ?? defaultCwd,
|
|
2670
|
-
pattern: source.pattern,
|
|
2671
|
-
negated: source.negated
|
|
2672
|
-
}));
|
|
2673
|
-
const source = {
|
|
2674
|
-
projectRoot: defaultCwd,
|
|
2675
|
-
base,
|
|
2676
|
-
baseFallbacks,
|
|
2677
|
-
css,
|
|
2678
|
-
dependencies: []
|
|
2679
|
-
};
|
|
2680
|
-
const designSystemKey = getTailwindV4DesignSystemCacheKey(source);
|
|
2681
|
-
const designSystem = await loadTailwindV4DesignSystem(source);
|
|
2682
|
-
const candidateCacheKey = createCandidateCacheKey(designSystemKey, providedOptions);
|
|
2683
|
-
const candidateCache = designSystemCandidateCache.get(candidateCacheKey) ?? /* @__PURE__ */ new Map();
|
|
2684
|
-
designSystemCandidateCache.set(candidateCacheKey, candidateCache);
|
|
2685
|
-
const candidates = await extractRawCandidates(sources, providedOptions.bareArbitraryValues === void 0 ? void 0 : { bareArbitraryValues: providedOptions.bareArbitraryValues });
|
|
2686
|
-
const inlineSources = extractTailwindV4InlineSourceCandidates(css);
|
|
2687
|
-
for (const candidate of inlineSources.included) candidates.push(candidate);
|
|
2688
|
-
for (const candidate of inlineSources.excluded) {
|
|
2689
|
-
let index = candidates.indexOf(candidate);
|
|
2690
|
-
while (index !== -1) {
|
|
2691
|
-
candidates.splice(index, 1);
|
|
2692
|
-
index = candidates.indexOf(candidate);
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
const validCandidates = [];
|
|
2696
|
-
const uncachedCandidates = [];
|
|
2697
|
-
for (const rawCandidate of candidates) {
|
|
2698
|
-
const cached = candidateCache.get(rawCandidate);
|
|
2699
|
-
if (cached === true) {
|
|
2700
|
-
validCandidates.push(rawCandidate);
|
|
2701
|
-
continue;
|
|
2702
|
-
}
|
|
2703
|
-
if (cached === false) continue;
|
|
2704
|
-
const bareArbitrary = resolveBareArbitraryValueCandidate(rawCandidate, providedOptions.bareArbitraryValues);
|
|
2705
|
-
if (designSystem.parseCandidate(rawCandidate).length > 0 || bareArbitrary && designSystem.parseCandidate(bareArbitrary.canonicalCandidate).length > 0) {
|
|
2706
|
-
uncachedCandidates.push(rawCandidate);
|
|
2707
|
-
continue;
|
|
2708
|
-
}
|
|
2709
|
-
candidateCache.set(rawCandidate, false);
|
|
2710
|
-
}
|
|
2711
|
-
if (uncachedCandidates.length === 0) return validCandidates;
|
|
2712
|
-
const validUncachedCandidates = resolveValidTailwindV4Candidates(designSystem, uncachedCandidates, providedOptions.bareArbitraryValues === void 0 ? void 0 : { bareArbitraryValues: providedOptions.bareArbitraryValues });
|
|
2713
|
-
for (const candidate of uncachedCandidates) {
|
|
2714
|
-
const isValid = validUncachedCandidates.has(candidate);
|
|
2715
|
-
candidateCache.set(candidate, isValid);
|
|
2716
|
-
if (!isValid) continue;
|
|
2717
|
-
validCandidates.push(candidate);
|
|
2718
|
-
}
|
|
2719
|
-
return validCandidates;
|
|
2720
|
-
}
|
|
2721
|
-
function buildLineOffsets(content) {
|
|
2722
|
-
const offsets = [0];
|
|
2723
|
-
for (let i = 0; i < content.length; i++) if (content[i] === "\n") offsets.push(i + 1);
|
|
2724
|
-
if (offsets[offsets.length - 1] !== content.length) offsets.push(content.length);
|
|
2725
|
-
return offsets;
|
|
2726
|
-
}
|
|
2727
|
-
function resolveLineMeta(content, offsets, index) {
|
|
2728
|
-
let low = 0;
|
|
2729
|
-
let high = offsets.length - 1;
|
|
2730
|
-
while (low <= high) {
|
|
2731
|
-
const mid = Math.floor((low + high) / 2);
|
|
2732
|
-
const start = offsets[mid];
|
|
2733
|
-
if (start === void 0) break;
|
|
2734
|
-
const nextStart = offsets[mid + 1] ?? content.length;
|
|
2735
|
-
if (index < start) {
|
|
2736
|
-
high = mid - 1;
|
|
2737
|
-
continue;
|
|
2738
|
-
}
|
|
2739
|
-
if (index >= nextStart) {
|
|
2740
|
-
low = mid + 1;
|
|
2741
|
-
continue;
|
|
2742
|
-
}
|
|
2743
|
-
const line = mid + 1;
|
|
2744
|
-
const column = index - start + 1;
|
|
2745
|
-
const lineEnd = content.indexOf("\n", start);
|
|
2746
|
-
return {
|
|
2747
|
-
line,
|
|
2748
|
-
column,
|
|
2749
|
-
lineText: content.slice(start, lineEnd === -1 ? content.length : lineEnd)
|
|
2750
|
-
};
|
|
2751
|
-
}
|
|
2752
|
-
const lastStart = offsets[offsets.length - 2] ?? 0;
|
|
2753
|
-
return {
|
|
2754
|
-
line: offsets.length - 1,
|
|
2755
|
-
column: index - lastStart + 1,
|
|
2756
|
-
lineText: content.slice(lastStart)
|
|
2757
|
-
};
|
|
2758
|
-
}
|
|
2759
|
-
function toExtension(filename) {
|
|
2760
|
-
return path.extname(filename).replace(/^\./, "") || "txt";
|
|
2761
|
-
}
|
|
2762
|
-
function toRelativeFile(cwd, filename) {
|
|
2763
|
-
const relative = path.relative(cwd, filename);
|
|
2764
|
-
return relative === "" ? path.basename(filename) : relative;
|
|
2765
|
-
}
|
|
2766
|
-
async function resolveScannerSources(options) {
|
|
2767
|
-
const cwd = options?.cwd ? path.resolve(options.cwd) : process.cwd();
|
|
2768
|
-
if (options?.sources?.length || options?.css === void 0) return {
|
|
2769
|
-
cwd,
|
|
2770
|
-
sources: normalizeTailwindV4ScannerSources(options?.sources, cwd, options?.ignoredSources)
|
|
2771
|
-
};
|
|
2772
|
-
const base = options.base ? path.resolve(options.base) : cwd;
|
|
2773
|
-
const { compiled } = await compileTailwindV4Source({
|
|
2774
|
-
projectRoot: cwd,
|
|
2775
|
-
base,
|
|
2776
|
-
baseFallbacks: options.baseFallbacks?.map((baseFallback) => path.resolve(baseFallback)) ?? [],
|
|
2777
|
-
css: options.css,
|
|
2778
|
-
dependencies: []
|
|
2779
|
-
});
|
|
2780
|
-
return {
|
|
2781
|
-
cwd,
|
|
2782
|
-
sources: normalizeTailwindV4ScannerSources(createTailwindV4CompiledSourceEntries(compiled.root, compiled.sources, base), cwd, options.ignoredSources)
|
|
2783
|
-
};
|
|
2784
|
-
}
|
|
2785
|
-
async function resolveProjectSourceFiles(options) {
|
|
2786
|
-
const { sources } = await resolveScannerSources(options);
|
|
2787
|
-
const { Scanner } = await getOxideModule();
|
|
2788
|
-
const files = new Scanner({ sources }).files ?? [];
|
|
2789
|
-
return options?.filter ? files.filter(options.filter) : files;
|
|
2790
|
-
}
|
|
2791
|
-
async function extractProjectCandidatesWithPositions(options) {
|
|
2792
|
-
const { cwd, sources } = await resolveScannerSources(options);
|
|
2793
|
-
const { Scanner } = await getOxideModule();
|
|
2794
|
-
const scanner = new Scanner({ sources });
|
|
2795
|
-
const files = scanner.files ?? [];
|
|
2796
|
-
const entries = [];
|
|
2797
|
-
const skipped = [];
|
|
2798
|
-
for (const file of files) {
|
|
2799
|
-
let content;
|
|
2800
|
-
try {
|
|
2801
|
-
content = await promises.readFile(file, "utf8");
|
|
2802
|
-
} catch (error) {
|
|
2803
|
-
skipped.push({
|
|
2804
|
-
file,
|
|
2805
|
-
reason: error instanceof Error ? error.message : "Unknown error"
|
|
2806
|
-
});
|
|
2807
|
-
continue;
|
|
2808
|
-
}
|
|
2809
|
-
const extension = toExtension(file);
|
|
2810
|
-
const matches = scanner.getCandidatesWithPositions({
|
|
2811
|
-
file,
|
|
2812
|
-
content,
|
|
2813
|
-
extension
|
|
2814
|
-
});
|
|
2815
|
-
if (!matches.length) continue;
|
|
2816
|
-
const offsets = buildLineOffsets(content);
|
|
2817
|
-
const relativeFile = toRelativeFile(cwd, file);
|
|
2818
|
-
for (const match of matches) {
|
|
2819
|
-
const info = resolveLineMeta(content, offsets, match.position);
|
|
2820
|
-
entries.push({
|
|
2821
|
-
rawCandidate: match.candidate,
|
|
2822
|
-
file,
|
|
2823
|
-
relativeFile,
|
|
2824
|
-
extension,
|
|
2825
|
-
start: match.position,
|
|
2826
|
-
end: match.position + match.candidate.length,
|
|
2827
|
-
length: match.candidate.length,
|
|
2828
|
-
line: info.line,
|
|
2829
|
-
column: info.column,
|
|
2830
|
-
lineText: info.lineText
|
|
2831
|
-
});
|
|
2832
|
-
}
|
|
2833
|
-
}
|
|
2834
|
-
return {
|
|
2835
|
-
entries,
|
|
2836
|
-
filesScanned: files.length,
|
|
2837
|
-
skippedFiles: skipped,
|
|
2838
|
-
sources
|
|
2839
|
-
};
|
|
2840
|
-
}
|
|
2841
|
-
function groupTokensByFile(report, options) {
|
|
2842
|
-
const key = options?.key ?? "relative";
|
|
2843
|
-
const stripAbsolute = options?.stripAbsolutePaths ?? key !== "absolute";
|
|
2844
|
-
return report.entries.reduce((acc, entry) => {
|
|
2845
|
-
const bucketKey = key === "absolute" ? entry.file : entry.relativeFile;
|
|
2846
|
-
const bucket = acc[bucketKey] ?? (acc[bucketKey] = []);
|
|
2847
|
-
const value = stripAbsolute ? {
|
|
2848
|
-
...entry,
|
|
2849
|
-
file: entry.relativeFile
|
|
2850
|
-
} : entry;
|
|
2851
|
-
bucket.push(value);
|
|
2852
|
-
return acc;
|
|
2853
|
-
}, {});
|
|
2854
|
-
}
|
|
2855
|
-
//#endregion
|
|
2856
1459
|
//#region src/utils.ts
|
|
2857
1460
|
function isObject(val) {
|
|
2858
1461
|
return val !== null && typeof val === "object" && Array.isArray(val) === false;
|
|
@@ -3720,9 +2323,9 @@ function createCollector(packageInfo, options, majorVersion, snapshotFactory) {
|
|
|
3720
2323
|
if (majorVersion === 4) return new TailwindV4Collector(packageInfo, options, snapshotFactory);
|
|
3721
2324
|
return new RuntimeCollector(packageInfo, options, majorVersion, snapshotFactory);
|
|
3722
2325
|
}
|
|
3723
|
-
function getPackageInfoFromCwd(packageName, cwd) {
|
|
2326
|
+
function getPackageInfoFromCwd(packageName, cwd, resolvePaths = []) {
|
|
3724
2327
|
try {
|
|
3725
|
-
const packageJsonPath = createRequire(path.join(cwd, "package.json")).resolve(`${packageName}/package.json
|
|
2328
|
+
const packageJsonPath = createRequire(path.join(cwd, "package.json")).resolve(`${packageName}/package.json`, { paths: resolvePaths });
|
|
3726
2329
|
const packageJson = fs.readJSONSync(packageJsonPath);
|
|
3727
2330
|
return {
|
|
3728
2331
|
name: packageName,
|
|
@@ -3737,7 +2340,7 @@ function getPackageInfoFromCwd(packageName, cwd) {
|
|
|
3737
2340
|
}
|
|
3738
2341
|
function getTailwindPackageInfo(options) {
|
|
3739
2342
|
const cwd = options.tailwind.cwd ?? options.projectRoot;
|
|
3740
|
-
return (options.tailwind.resolve?.paths?.length ? getPackageInfoFromCwd(options.tailwind.packageName, cwd) : void 0) ?? getPackageInfoSync(options.tailwind.packageName, options.tailwind.resolve);
|
|
2343
|
+
return (options.tailwind.resolve?.paths?.length ? getPackageInfoFromCwd(options.tailwind.packageName, cwd, options.tailwind.resolve.paths) : void 0) ?? getPackageInfoSync(options.tailwind.packageName, options.tailwind.resolve);
|
|
3741
2344
|
}
|
|
3742
2345
|
var TailwindcssPatcher = class {
|
|
3743
2346
|
options;
|
|
@@ -4528,4 +3131,4 @@ var ValidateCommandError = class extends Error {
|
|
|
4528
3131
|
}
|
|
4529
3132
|
};
|
|
4530
3133
|
//#endregion
|
|
4531
|
-
export {
|
|
3134
|
+
export { resolveProjectSourceFiles as C, CacheStore as D, normalizeOptions as E, logger as O, groupTokensByFile as S, loadWorkspaceConfigModule as T, extractRawCandidates as _, tailwindcssPatchCommands as a, extractSourceCandidatesWithPositions as b, MIGRATION_REPORT_KIND as c, getPatchStatusReport as d, runTailwindBuild as f, extractProjectCandidatesWithPositions as g, collectClassesFromTailwindV4 as h, classifyValidateError as i, MIGRATION_REPORT_SCHEMA_VERSION as l, collectClassesFromContexts as m, VALIDATE_FAILURE_REASONS as n, migrateConfigFiles as o, loadRuntimeContexts as p, ValidateCommandError as r, restoreConfigFiles as s, VALIDATE_EXIT_CODES as t, TailwindcssPatcher as u, extractRawCandidatesWithPositions as v, loadPatchOptionsForWorkspace as w, extractValidCandidates as x, extractSourceCandidates as y };
|