tailwind-canonical 0.6.0 → 0.7.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/README.md +91 -18
- package/dist/cli/cli.d.ts +0 -1
- package/dist/cli/cli.js +111 -87
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +0 -1
- package/dist/core/analyzer.d.ts +0 -1
- package/dist/core/analyzer.js +0 -1
- package/dist/core/class-strings.d.ts +0 -1
- package/dist/core/class-strings.js +0 -1
- package/dist/core/config.d.ts +2 -3
- package/dist/core/config.js +9 -2
- package/dist/core/consistency.d.ts +0 -1
- package/dist/core/consistency.js +1 -6
- package/dist/core/deduplicator.d.ts +0 -1
- package/dist/core/deduplicator.js +10 -6
- package/dist/core/fixer.d.ts +0 -1
- package/dist/core/fixer.js +0 -1
- package/dist/core/lexicon.d.ts +1 -1
- package/dist/core/lexicon.js +1 -2
- package/dist/core/merger.d.ts +0 -1
- package/dist/core/merger.js +35 -29
- package/dist/core/rules.d.ts +2 -1
- package/dist/core/rules.js +56 -1
- package/dist/core/scanner.d.ts +0 -1
- package/dist/core/scanner.js +0 -1
- package/dist/core/sorter.d.ts +0 -1
- package/dist/core/sorter.js +5 -3
- package/dist/core/suppressions.d.ts +0 -1
- package/dist/core/suppressions.js +0 -1
- package/dist/core/typos.d.ts +0 -1
- package/dist/core/typos.js +0 -1
- package/dist/eslint/plugin.d.ts +0 -1
- package/dist/eslint/plugin.js +2 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/io/analyzer.d.ts +0 -1
- package/dist/io/analyzer.js +0 -1
- package/dist/io/config.d.ts +9 -1
- package/dist/io/config.js +66 -5
- package/dist/io/consistency.d.ts +0 -1
- package/dist/io/consistency.js +0 -1
- package/dist/io/deduplicator.d.ts +0 -1
- package/dist/io/deduplicator.js +0 -1
- package/dist/io/fixer.d.ts +0 -1
- package/dist/io/fixer.js +0 -1
- package/dist/io/merger.d.ts +0 -1
- package/dist/io/merger.js +0 -1
- package/dist/io/scanner.d.ts +0 -1
- package/dist/io/scanner.js +0 -1
- package/dist/io/sorter.d.ts +0 -1
- package/dist/io/sorter.js +0 -1
- package/dist/io/typos.d.ts +0 -1
- package/dist/io/typos.js +0 -1
- package/package.json +10 -9
- package/dist/cli/cli.d.ts.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/core/analyzer.d.ts.map +0 -1
- package/dist/core/analyzer.js.map +0 -1
- package/dist/core/class-strings.d.ts.map +0 -1
- package/dist/core/class-strings.js.map +0 -1
- package/dist/core/config.d.ts.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/consistency.d.ts.map +0 -1
- package/dist/core/consistency.js.map +0 -1
- package/dist/core/deduplicator.d.ts.map +0 -1
- package/dist/core/deduplicator.js.map +0 -1
- package/dist/core/fixer.d.ts.map +0 -1
- package/dist/core/fixer.js.map +0 -1
- package/dist/core/lexicon.d.ts.map +0 -1
- package/dist/core/lexicon.js.map +0 -1
- package/dist/core/merger.d.ts.map +0 -1
- package/dist/core/merger.js.map +0 -1
- package/dist/core/rules.d.ts.map +0 -1
- package/dist/core/rules.js.map +0 -1
- package/dist/core/scanner.d.ts.map +0 -1
- package/dist/core/scanner.js.map +0 -1
- package/dist/core/sorter.d.ts.map +0 -1
- package/dist/core/sorter.js.map +0 -1
- package/dist/core/suppressions.d.ts.map +0 -1
- package/dist/core/suppressions.js.map +0 -1
- package/dist/core/typos.d.ts.map +0 -1
- package/dist/core/typos.js.map +0 -1
- package/dist/eslint/plugin.d.ts.map +0 -1
- package/dist/eslint/plugin.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/io/analyzer.d.ts.map +0 -1
- package/dist/io/analyzer.js.map +0 -1
- package/dist/io/config.d.ts.map +0 -1
- package/dist/io/config.js.map +0 -1
- package/dist/io/consistency.d.ts.map +0 -1
- package/dist/io/consistency.js.map +0 -1
- package/dist/io/deduplicator.d.ts.map +0 -1
- package/dist/io/deduplicator.js.map +0 -1
- package/dist/io/fixer.d.ts.map +0 -1
- package/dist/io/fixer.js.map +0 -1
- package/dist/io/merger.d.ts.map +0 -1
- package/dist/io/merger.js.map +0 -1
- package/dist/io/scanner.d.ts.map +0 -1
- package/dist/io/scanner.js.map +0 -1
- package/dist/io/sorter.d.ts.map +0 -1
- package/dist/io/sorter.js.map +0 -1
- package/dist/io/typos.d.ts.map +0 -1
- package/dist/io/typos.js.map +0 -1
package/dist/core/merger.js
CHANGED
|
@@ -26,20 +26,32 @@ function parseClassToken(token) {
|
|
|
26
26
|
base: parts.at(-1) ?? token,
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
function isArbitraryTextSize(base) {
|
|
33
|
-
return /^!?text-\[-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|ch|ex|lh|rlh|vw|vh|vmin|vmax|vi|vb|svw|lvw|dvw|svh|lvh|dvh)\]$/.test(base);
|
|
34
|
-
}
|
|
35
|
-
function customTextClassSet(customTextTokens) {
|
|
36
|
-
return new Set(Object.values(customTextTokens ?? {}).map((token) => `text-${token}`));
|
|
37
|
-
}
|
|
29
|
+
const RE_LEADING = /^!?leading-/;
|
|
30
|
+
const RE_ARBITRARY_TEXT_SIZE = /^!?text-\[-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|ch|ex|lh|rlh|vw|vh|vmin|vmax|vi|vb|svw|lvw|dvw|svh|lvh|dvh)\]$/;
|
|
38
31
|
function isUnsafeTextSize(base, customTextClasses) {
|
|
39
32
|
const normalized = base.startsWith('!') ? base.slice(1) : base;
|
|
40
|
-
return customTextClasses.has(normalized) ||
|
|
33
|
+
return (customTextClasses.has(normalized) || RE_ARBITRARY_TEXT_SIZE.test(normalized));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Last `leading-*` class declared before `cls` in the original string that
|
|
37
|
+
* twMerge dropped, matching `cls`'s variant modifiers. Scans backwards from
|
|
38
|
+
* `cls`'s own position — a leading declared after it never applied to it.
|
|
39
|
+
*/
|
|
40
|
+
function lastLeadingBefore(originalClasses, cls, mergedTokens) {
|
|
41
|
+
// twMerge only filters tokens, never synthesises one, so `cls` is always
|
|
42
|
+
// present in the original — `findIndex` cannot return -1 here.
|
|
43
|
+
const at = originalClasses.findIndex(({ token }) => token === cls.token);
|
|
44
|
+
for (let i = at - 1; i >= 0; i -= 1) {
|
|
45
|
+
const candidate = originalClasses[i];
|
|
46
|
+
if (RE_LEADING.test(candidate.base) &&
|
|
47
|
+
candidate.modifiers === cls.modifiers &&
|
|
48
|
+
!mergedTokens.has(candidate.token)) {
|
|
49
|
+
return candidate;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
41
53
|
}
|
|
42
|
-
function restoreLeadingForUnsafeTextSizes(original, merged,
|
|
54
|
+
function restoreLeadingForUnsafeTextSizes(original, merged, customTextClasses) {
|
|
43
55
|
const originalClasses = original
|
|
44
56
|
.split(/\s+/)
|
|
45
57
|
.filter(Boolean)
|
|
@@ -49,34 +61,28 @@ function restoreLeadingForUnsafeTextSizes(original, merged, opts) {
|
|
|
49
61
|
.filter(Boolean)
|
|
50
62
|
.map(parseClassToken);
|
|
51
63
|
const mergedTokens = new Set(mergedClasses.map(({ token }) => token));
|
|
52
|
-
const
|
|
64
|
+
const keptLeadingModifiers = new Set(mergedClasses
|
|
65
|
+
.filter(({ base }) => RE_LEADING.test(base))
|
|
66
|
+
.map(({ modifiers }) => modifiers));
|
|
53
67
|
const restored = [];
|
|
54
68
|
for (const cls of mergedClasses) {
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
isUnsafeTextSize(cls.base, customTextClasses) &&
|
|
63
|
-
!mergedClasses.some((candidate) => isLeadingClass(candidate.base) &&
|
|
64
|
-
candidate.modifiers === cls.modifiers)) {
|
|
65
|
-
restored.push(leading.token);
|
|
66
|
-
mergedTokens.add(leading.token);
|
|
69
|
+
if (isUnsafeTextSize(cls.base, customTextClasses) &&
|
|
70
|
+
!keptLeadingModifiers.has(cls.modifiers)) {
|
|
71
|
+
const leading = lastLeadingBefore(originalClasses, cls, mergedTokens);
|
|
72
|
+
if (leading) {
|
|
73
|
+
restored.push(leading.token);
|
|
74
|
+
mergedTokens.add(leading.token);
|
|
75
|
+
}
|
|
67
76
|
}
|
|
68
77
|
restored.push(cls.token);
|
|
69
78
|
}
|
|
70
79
|
return restored.join(' ');
|
|
71
80
|
}
|
|
72
81
|
export function mergeContent(content, twMerge, opts = {}) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return restoreLeadingForUnsafeTextSizes(classes, merged, opts);
|
|
76
|
-
}, {
|
|
82
|
+
const customTextClasses = new Set(Object.values(opts.customTextTokens ?? {}).map((token) => `text-${token}`));
|
|
83
|
+
return replaceClassStrings(content, (classes) => restoreLeadingForUnsafeTextSizes(classes, twMerge(classes), customTextClasses), {
|
|
77
84
|
...opts,
|
|
78
85
|
isSuppressed: makeLineSuppressor(content),
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
88
|
export { mergeFile } from '../io/merger.js';
|
|
82
|
-
//# sourceMappingURL=merger.js.map
|
package/dist/core/rules.d.ts
CHANGED
|
@@ -40,7 +40,8 @@ export type Config = {
|
|
|
40
40
|
rareScaleMaxFiles?: number;
|
|
41
41
|
rareScaleMaxCount?: number;
|
|
42
42
|
defaultCommand?: DefaultCommandConfig;
|
|
43
|
+
/** Target Tailwind major. v3 restricts suggestions to its discrete scale. */
|
|
44
|
+
tailwindVersion?: 3 | 4;
|
|
43
45
|
};
|
|
44
46
|
export declare function suggestCanonical(cls: string, config?: Config): Suggestion | null;
|
|
45
47
|
export {};
|
|
46
|
-
//# sourceMappingURL=rules.d.ts.map
|
package/dist/core/rules.js
CHANGED
|
@@ -102,6 +102,47 @@ const FRACTION_RE = new RegExp(`^(${FRACTION_PREFIXES.join('|')})-\\[(\\d+(?:\\.
|
|
|
102
102
|
const OPACITY_SCALE = new Set([
|
|
103
103
|
0, 5, 10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 95, 100,
|
|
104
104
|
]);
|
|
105
|
+
/**
|
|
106
|
+
* Numeric spacing steps the ÷4 rule may emit that Tailwind v3 actually ships.
|
|
107
|
+
* v4 derives every step from `calc(var(--spacing) * n)`, so any integer works
|
|
108
|
+
* there; v3 ships a discrete scale and a class outside it generates no CSS.
|
|
109
|
+
* The ÷4 rule only ever yields integers, so v3's half steps are unreachable
|
|
110
|
+
* and absent here. Measured by compiling tailwindcss@3.3.7.
|
|
111
|
+
*/
|
|
112
|
+
const V3_SPACING_STEPS = new Set([
|
|
113
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44,
|
|
114
|
+
48, 52, 56, 60, 64, 72, 80, 96,
|
|
115
|
+
]);
|
|
116
|
+
/** No numeric spacing scale at all in v3.3, the documented floor. */
|
|
117
|
+
const V3_UNSCALED_SPACING_PREFIXES = new Set(['size']);
|
|
118
|
+
/** Only the zero step exists in v3.3; the scale itself arrived after 3.3. */
|
|
119
|
+
const V3_ZERO_ONLY_SPACING_PREFIXES = new Set(['min-w', 'max-w', 'min-h']);
|
|
120
|
+
const V3_INSET_FRACTIONS = ['1/2', '1/3', '2/3', '1/4', '3/4'];
|
|
121
|
+
const V3_HEIGHT_FRACTIONS = [
|
|
122
|
+
...V3_INSET_FRACTIONS,
|
|
123
|
+
'1/5',
|
|
124
|
+
'2/5',
|
|
125
|
+
'3/5',
|
|
126
|
+
'4/5',
|
|
127
|
+
'1/6',
|
|
128
|
+
'5/6',
|
|
129
|
+
];
|
|
130
|
+
/**
|
|
131
|
+
* Fractions each utility ships in v3.3 — the scale differs per utility, not
|
|
132
|
+
* just per family, so this is keyed on both. A prefix absent from this table
|
|
133
|
+
* has no fraction scale at all (`min-w`, `max-w`, `min-h`, `max-h`).
|
|
134
|
+
*/
|
|
135
|
+
const V3_FRACTIONS_BY_PREFIX = {
|
|
136
|
+
w: new Set([...V3_HEIGHT_FRACTIONS, '1/12', '11/12']),
|
|
137
|
+
h: new Set(V3_HEIGHT_FRACTIONS),
|
|
138
|
+
inset: new Set(V3_INSET_FRACTIONS),
|
|
139
|
+
top: new Set(V3_INSET_FRACTIONS),
|
|
140
|
+
left: new Set(V3_INSET_FRACTIONS),
|
|
141
|
+
right: new Set(V3_INSET_FRACTIONS),
|
|
142
|
+
bottom: new Set(V3_INSET_FRACTIONS),
|
|
143
|
+
'translate-x': new Set(V3_INSET_FRACTIONS),
|
|
144
|
+
'translate-y': new Set(V3_INSET_FRACTIONS),
|
|
145
|
+
};
|
|
105
146
|
function remToPx(rem) {
|
|
106
147
|
const px = rem * 16;
|
|
107
148
|
return Number.isInteger(px) ? px : null;
|
|
@@ -114,11 +155,20 @@ function isIgnored(cls, patterns) {
|
|
|
114
155
|
return re.test(cls);
|
|
115
156
|
});
|
|
116
157
|
}
|
|
158
|
+
/** True when the ÷4 result would be a class v3 never generates. */
|
|
159
|
+
function isMissingInV3(prefix, step) {
|
|
160
|
+
if (V3_UNSCALED_SPACING_PREFIXES.has(prefix))
|
|
161
|
+
return true;
|
|
162
|
+
if (V3_ZERO_ONLY_SPACING_PREFIXES.has(prefix))
|
|
163
|
+
return step !== 0;
|
|
164
|
+
return !V3_SPACING_STEPS.has(step);
|
|
165
|
+
}
|
|
117
166
|
export function suggestCanonical(cls, config = {}) {
|
|
118
167
|
if (isIgnored(cls, config.ignorePatterns))
|
|
119
168
|
return null;
|
|
120
169
|
const textTokens = { ...TEXT_SIZE_MAP, ...config.customTextTokens };
|
|
121
170
|
const spacingTokens = config.customSpacingTokens ?? {};
|
|
171
|
+
const v3 = config.tailwindVersion === 3;
|
|
122
172
|
// text-[Npx]
|
|
123
173
|
const textPxMatch = cls.match(/^text-\[(\d+)px\]$/);
|
|
124
174
|
if (textPxMatch) {
|
|
@@ -160,6 +210,8 @@ export function suggestCanonical(cls, config = {}) {
|
|
|
160
210
|
};
|
|
161
211
|
}
|
|
162
212
|
if (px % 4 === 0) {
|
|
213
|
+
if (v3 && isMissingInV3(prefix, px / 4))
|
|
214
|
+
return null;
|
|
163
215
|
return {
|
|
164
216
|
original: cls,
|
|
165
217
|
canonical: `${prefix}-${px / 4}`,
|
|
@@ -183,6 +235,8 @@ export function suggestCanonical(cls, config = {}) {
|
|
|
183
235
|
};
|
|
184
236
|
}
|
|
185
237
|
if (px % 4 === 0) {
|
|
238
|
+
if (v3 && isMissingInV3(prefix, px / 4))
|
|
239
|
+
return null;
|
|
186
240
|
return {
|
|
187
241
|
original: cls,
|
|
188
242
|
canonical: `${prefix}-${px / 4}`,
|
|
@@ -199,6 +253,8 @@ export function suggestCanonical(cls, config = {}) {
|
|
|
199
253
|
const fraction = FRACTION_MAP[pct];
|
|
200
254
|
if (!fraction)
|
|
201
255
|
return null;
|
|
256
|
+
if (v3 && !V3_FRACTIONS_BY_PREFIX[prefix]?.has(fraction))
|
|
257
|
+
return null;
|
|
202
258
|
return {
|
|
203
259
|
original: cls,
|
|
204
260
|
canonical: `${prefix}-${fraction}`,
|
|
@@ -238,4 +294,3 @@ export function suggestCanonical(cls, config = {}) {
|
|
|
238
294
|
}
|
|
239
295
|
return null;
|
|
240
296
|
}
|
|
241
|
-
//# sourceMappingURL=rules.js.map
|
package/dist/core/scanner.d.ts
CHANGED
package/dist/core/scanner.js
CHANGED
package/dist/core/sorter.d.ts
CHANGED
package/dist/core/sorter.js
CHANGED
|
@@ -37,6 +37,7 @@ const TYPOGRAPHY_KEYWORDS = new Set([
|
|
|
37
37
|
'antialiased',
|
|
38
38
|
'subpixel-antialiased',
|
|
39
39
|
]);
|
|
40
|
+
const RE_DARK_PRINT = /^(dark|print)$/;
|
|
40
41
|
const TEXT_SIZES = /^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl|left|center|right|justify|start|end)$/;
|
|
41
42
|
const RE_LAYOUT = /^(overflow|overscroll|object|float|clear|isolation|box|columns)[-]/;
|
|
42
43
|
const RE_INSET = /^(inset|top|right|bottom|left|z)[-]/;
|
|
@@ -98,7 +99,9 @@ function getCategory(cls) {
|
|
|
98
99
|
return 'colors';
|
|
99
100
|
if (base === 'shadow' ||
|
|
100
101
|
base === 'blur' ||
|
|
101
|
-
|
|
102
|
+
base === 'grayscale' ||
|
|
103
|
+
base === 'invert' ||
|
|
104
|
+
base === 'sepia' ||
|
|
102
105
|
RE_EFFECTS.test(base))
|
|
103
106
|
return 'effects';
|
|
104
107
|
if (base === 'transition' || RE_TRANSITIONS.test(base))
|
|
@@ -128,7 +131,7 @@ function getVariantOrder(cls) {
|
|
|
128
131
|
const segments = cls.slice(0, cls.lastIndexOf(':')).split(':');
|
|
129
132
|
if (segments.some((s) => RE_BREAKPOINTS.test(s)))
|
|
130
133
|
return 1;
|
|
131
|
-
if (segments.some((s) =>
|
|
134
|
+
if (segments.some((s) => RE_DARK_PRINT.test(s)))
|
|
132
135
|
return 2;
|
|
133
136
|
return 3;
|
|
134
137
|
}
|
|
@@ -163,4 +166,3 @@ export function sortContent(content, opts = {}, sortOrder) {
|
|
|
163
166
|
});
|
|
164
167
|
}
|
|
165
168
|
export { sortFile } from '../io/sorter.js';
|
|
166
|
-
//# sourceMappingURL=sorter.js.map
|
package/dist/core/typos.d.ts
CHANGED
|
@@ -11,4 +11,3 @@ export declare function detectTypo(cls: string, extraColors?: ReadonlySet<string
|
|
|
11
11
|
} | null;
|
|
12
12
|
export declare function analyzeTyposContent(filePath: string, content: string, config?: Config): TypoFinding[];
|
|
13
13
|
export { analyzeTyposFile } from '../io/typos.js';
|
|
14
|
-
//# sourceMappingURL=typos.d.ts.map
|
package/dist/core/typos.js
CHANGED
package/dist/eslint/plugin.d.ts
CHANGED
package/dist/eslint/plugin.js
CHANGED
|
@@ -48,7 +48,7 @@ const noArbitraryCanonical = {
|
|
|
48
48
|
// Schema accepts the full tailwind-canonical Config so a single shared
|
|
49
49
|
// config object can be passed as rule options without schema errors (#42).
|
|
50
50
|
// Honored by this rule (via suggestCanonical): customTextTokens,
|
|
51
|
-
// customSpacingTokens, ignorePatterns.
|
|
51
|
+
// customSpacingTokens, ignorePatterns, tailwindVersion.
|
|
52
52
|
// Accepted but ignored here (CLI-only): functionNames, attributeNames,
|
|
53
53
|
// sortOrder.
|
|
54
54
|
schema: [
|
|
@@ -58,6 +58,7 @@ const noArbitraryCanonical = {
|
|
|
58
58
|
customTextTokens: { type: 'object' },
|
|
59
59
|
customSpacingTokens: { type: 'object' },
|
|
60
60
|
ignorePatterns: { type: 'array' },
|
|
61
|
+
tailwindVersion: { enum: [3, 4] },
|
|
61
62
|
functionNames: { type: 'array', items: { type: 'string' } },
|
|
62
63
|
attributeNames: { type: 'array', items: { type: 'string' } },
|
|
63
64
|
sortOrder: { type: 'array', items: { type: 'string' } },
|
|
@@ -151,4 +152,3 @@ plugin.configs.recommended = {
|
|
|
151
152
|
},
|
|
152
153
|
};
|
|
153
154
|
export default plugin;
|
|
154
|
-
//# sourceMappingURL=plugin.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -14,4 +14,3 @@ export type { SortCategory } from './core/sorter.js';
|
|
|
14
14
|
export { DEFAULT_SORT_ORDER, sortClasses, sortFile } from './core/sorter.js';
|
|
15
15
|
export type { TypoFinding } from './core/typos.js';
|
|
16
16
|
export { analyzeTyposFile, detectTypo } from './core/typos.js';
|
|
17
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -16,4 +16,3 @@ export { suggestCanonical } from './core/rules.js';
|
|
|
16
16
|
export { resolveTargets, scanFiles } from './core/scanner.js';
|
|
17
17
|
export { DEFAULT_SORT_ORDER, sortClasses, sortFile } from './core/sorter.js';
|
|
18
18
|
export { analyzeTyposFile, detectTypo } from './core/typos.js';
|
|
19
|
-
//# sourceMappingURL=index.js.map
|
package/dist/io/analyzer.d.ts
CHANGED
package/dist/io/analyzer.js
CHANGED
package/dist/io/config.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
import type { Config } from '../core/rules.js';
|
|
2
|
+
/**
|
|
3
|
+
* The config extension that actually loads here. `.ts`/`.mts` need Node type
|
|
4
|
+
* stripping (>=22.18, or >=22.6 behind --experimental-strip-types), so short
|
|
5
|
+
* of that we scaffold plain ESM instead — `.mjs` under CommonJS, `.js` where
|
|
6
|
+
* the nearest package.json already declares `"type": "module"`. Both load on
|
|
7
|
+
* every supported Node, so preferring them when a flag is in play costs
|
|
8
|
+
* nothing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveInitFilename(cwd: string): string;
|
|
2
11
|
export declare function loadConfig(cwd: string): Promise<Config>;
|
|
3
|
-
//# sourceMappingURL=config.d.ts.map
|
package/dist/io/config.js
CHANGED
|
@@ -1,7 +1,56 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { CONFIG_FILENAMES, validateConfig } from '../core/config.js';
|
|
5
|
+
/** The `type` of the package.json that governs `dir`, per Node resolution. */
|
|
6
|
+
function nearestPackageType(dir) {
|
|
7
|
+
let current = dir;
|
|
8
|
+
while (true) {
|
|
9
|
+
const manifest = join(current, 'package.json');
|
|
10
|
+
if (existsSync(manifest)) {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(readFileSync(manifest, 'utf8'));
|
|
13
|
+
return parsed.type === 'module' ? 'module' : 'commonjs';
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return 'commonjs';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const parent = dirname(current);
|
|
20
|
+
if (parent === current)
|
|
21
|
+
return 'commonjs';
|
|
22
|
+
current = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const STRIP_FLAG = /--experimental-(strip|transform)-types/;
|
|
26
|
+
/**
|
|
27
|
+
* Whether `.ts` loads on a bare `node`, as opposed to only under a flag.
|
|
28
|
+
* `process.features.typescript` is also `"strip"` when the flag supplied it,
|
|
29
|
+
* so a config scaffolded in a flagged process would fail on every later
|
|
30
|
+
* unflagged run — including plain `npx tailwind-canonical`.
|
|
31
|
+
*/
|
|
32
|
+
function stripsTypesUnflagged() {
|
|
33
|
+
if (!process.features.typescript)
|
|
34
|
+
return false;
|
|
35
|
+
if (process.execArgv.some((arg) => STRIP_FLAG.test(arg)))
|
|
36
|
+
return false;
|
|
37
|
+
return !STRIP_FLAG.test(process.env.NODE_OPTIONS ?? '');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The config extension that actually loads here. `.ts`/`.mts` need Node type
|
|
41
|
+
* stripping (>=22.18, or >=22.6 behind --experimental-strip-types), so short
|
|
42
|
+
* of that we scaffold plain ESM instead — `.mjs` under CommonJS, `.js` where
|
|
43
|
+
* the nearest package.json already declares `"type": "module"`. Both load on
|
|
44
|
+
* every supported Node, so preferring them when a flag is in play costs
|
|
45
|
+
* nothing.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveInitFilename(cwd) {
|
|
48
|
+
if (stripsTypesUnflagged())
|
|
49
|
+
return 'tailwind-canonical.config.ts';
|
|
50
|
+
return nearestPackageType(cwd) === 'module'
|
|
51
|
+
? 'tailwind-canonical.config.js'
|
|
52
|
+
: 'tailwind-canonical.config.mjs';
|
|
53
|
+
}
|
|
5
54
|
function findConfigPath(cwd) {
|
|
6
55
|
let dir = cwd;
|
|
7
56
|
while (true) {
|
|
@@ -26,13 +75,25 @@ export async function loadConfig(cwd) {
|
|
|
26
75
|
mod = await import(pathToFileURL(path).href);
|
|
27
76
|
}
|
|
28
77
|
catch (err) {
|
|
29
|
-
|
|
78
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
+
const type = nearestPackageType(dirname(path));
|
|
80
|
+
if (/\.m?ts$/.test(filename) &&
|
|
30
81
|
err.code === 'ERR_UNKNOWN_FILE_EXTENSION') {
|
|
31
|
-
const
|
|
32
|
-
|
|
82
|
+
const js = type === 'module'
|
|
83
|
+
? 'tailwind-canonical.config.js'
|
|
84
|
+
: 'tailwind-canonical.config.mjs';
|
|
85
|
+
throw new Error(`Loading ${filename} failed on this Node version (type stripping requires Node >=22.18, or >=22.6 with --experimental-strip-types). Either upgrade Node, or rename the config to ${js} and drop its TypeScript-only syntax — the "import type" line and the trailing "satisfies Config" — since a bare rename leaves it unparseable. Original error: ${msg}`);
|
|
86
|
+
}
|
|
87
|
+
if (err instanceof SyntaxError &&
|
|
88
|
+
/\bexport\b|\bimport\b/.test(msg) &&
|
|
89
|
+
!/\.m[tj]s$/.test(filename) &&
|
|
90
|
+
type !== 'module') {
|
|
91
|
+
const esm = filename.endsWith('.ts')
|
|
92
|
+
? 'tailwind-canonical.config.mts'
|
|
93
|
+
: 'tailwind-canonical.config.mjs';
|
|
94
|
+
throw new Error(`${filename} uses ESM syntax but is loaded as CommonJS, because the nearest package.json has no "type": "module". Rename it to ${esm}, or add "type": "module" to your package.json. Original error: ${msg}`);
|
|
33
95
|
}
|
|
34
96
|
throw err;
|
|
35
97
|
}
|
|
36
98
|
return validateConfig(mod.default, filename);
|
|
37
99
|
}
|
|
38
|
-
//# sourceMappingURL=config.js.map
|
package/dist/io/consistency.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { type ConsistencyOptions, type ConsistencyReport } from '../core/consistency.js';
|
|
2
2
|
import type { Config } from '../core/rules.js';
|
|
3
3
|
export declare function analyzeConsistencyFiles(filePaths: string[], config?: Config, options?: ConsistencyOptions, onError?: (file: string, err: unknown) => void): ConsistencyReport;
|
|
4
|
-
//# sourceMappingURL=consistency.d.ts.map
|
package/dist/io/consistency.js
CHANGED
package/dist/io/deduplicator.js
CHANGED
package/dist/io/fixer.d.ts
CHANGED
package/dist/io/fixer.js
CHANGED
package/dist/io/merger.d.ts
CHANGED
package/dist/io/merger.js
CHANGED
package/dist/io/scanner.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { type ScanOptions } from '../core/scanner.js';
|
|
2
2
|
export declare function scanFiles(target: string, options?: ScanOptions): string[];
|
|
3
3
|
export declare function resolveTargets(patterns: string[], options?: ScanOptions): Promise<string[]>;
|
|
4
|
-
//# sourceMappingURL=scanner.d.ts.map
|
package/dist/io/scanner.js
CHANGED
package/dist/io/sorter.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import type { ClassStringOpts } from '../core/class-strings.js';
|
|
2
2
|
import { type SortCategory } from '../core/sorter.js';
|
|
3
3
|
export declare function sortFile(filePath: string, opts?: ClassStringOpts, sortOrder?: SortCategory[]): number;
|
|
4
|
-
//# sourceMappingURL=sorter.d.ts.map
|
package/dist/io/sorter.js
CHANGED
package/dist/io/typos.d.ts
CHANGED
package/dist/io/typos.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailwind-canonical",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Lint and auto-fix Tailwind CSS arbitrary values that have canonical equivalents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"./eslint": {
|
|
14
14
|
"types": "./dist/eslint/plugin.d.ts",
|
|
15
15
|
"import": "./dist/eslint/plugin.js"
|
|
16
|
-
}
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
17
18
|
},
|
|
18
19
|
"bin": {
|
|
19
20
|
"tailwind-canonical": "./dist/cli/index.js"
|
|
@@ -53,14 +54,14 @@
|
|
|
53
54
|
],
|
|
54
55
|
"license": "MIT",
|
|
55
56
|
"devDependencies": {
|
|
56
|
-
"@biomejs/biome": "^2.
|
|
57
|
+
"@biomejs/biome": "^2.5.11",
|
|
57
58
|
"@types/estree": "^1.0.9",
|
|
58
|
-
"@types/node": "^22.
|
|
59
|
-
"knip": "^6.
|
|
60
|
-
"lefthook": "^2.1.
|
|
59
|
+
"@types/node": "^22.20.1",
|
|
60
|
+
"knip": "^6.34.0",
|
|
61
|
+
"lefthook": "^2.1.12",
|
|
61
62
|
"tailwind-merge": "^3.6.0",
|
|
62
|
-
"tsx": "^4.
|
|
63
|
-
"typescript": "^6.0.
|
|
63
|
+
"tsx": "^4.23.13",
|
|
64
|
+
"typescript": "^6.0.3"
|
|
64
65
|
},
|
|
65
66
|
"peerDependencies": {
|
|
66
67
|
"eslint": ">=8.0.0",
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
}
|
|
76
77
|
},
|
|
77
78
|
"scripts": {
|
|
78
|
-
"build": "tsc",
|
|
79
|
+
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc",
|
|
79
80
|
"dev": "tsc --watch",
|
|
80
81
|
"test": "node --import=tsx/esm --test \"src/**/*.test.ts\"",
|
|
81
82
|
"typecheck": "tsc --noEmit",
|
package/dist/cli/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":"AAgEA,MAAM,MAAM,IAAI,GAAG;IACjB,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B,CAAC;AAQF,MAAM,MAAM,SAAS,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEjE,KAAK,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE1C,KAAK,KAAK,GAAG;IACX,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAyJF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,KAAK,CAqE/C;AAgDD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAyBnD;AAgfD,wBAAsB,GAAG,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,IAAkB,GACvB,OAAO,CAAC,SAAS,CAAC,CA0RpB"}
|