tailwind-canonical 0.7.1 → 0.9.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 +131 -11
- package/dist/cli/cli.js +47 -5
- package/dist/cli/index.js +1 -1
- package/dist/cli/watch.d.ts +12 -2
- package/dist/cli/watch.js +144 -24
- package/dist/core/class-strings.js +547 -49
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +4 -1
- package/dist/core/consistency.d.ts +5 -0
- package/dist/core/consistency.js +22 -15
- package/dist/core/deduplicator.js +4 -0
- package/dist/core/merger.d.ts +1 -0
- package/dist/core/merger.js +5 -2
- package/dist/core/rules.d.ts +7 -0
- package/dist/core/rules.js +444 -9
- package/dist/core/scanner.d.ts +0 -1
- package/dist/core/scanner.js +1 -50
- package/dist/eslint/plugin.d.ts +1 -1
- package/dist/eslint/plugin.js +105 -28
- package/dist/io/config.d.ts +4 -1
- package/dist/io/config.js +45 -4
- package/dist/io/consistency.js +4 -6
- package/dist/io/scanner.js +26 -10
- package/package.json +8 -6
package/dist/core/config.js
CHANGED
|
@@ -7,6 +7,7 @@ export const CONFIG_FILENAMES = [
|
|
|
7
7
|
'tailwind-canonical.config.mjs',
|
|
8
8
|
];
|
|
9
9
|
const KNOWN_KEYS = [
|
|
10
|
+
'useDefaultTheme',
|
|
10
11
|
'customTextTokens',
|
|
11
12
|
'customSpacingTokens',
|
|
12
13
|
'ignorePatterns',
|
|
@@ -141,6 +142,8 @@ export function validateConfig(input, filename = CONFIG_FILENAME) {
|
|
|
141
142
|
}
|
|
142
143
|
const cfg = input;
|
|
143
144
|
assertKnownKeys(cfg, KNOWN_KEYS, 'unknown key', filename);
|
|
145
|
+
if ('useDefaultTheme' in cfg && typeof cfg.useDefaultTheme !== 'boolean')
|
|
146
|
+
fail(filename, 'useDefaultTheme must be a boolean');
|
|
144
147
|
if ('customTextTokens' in cfg)
|
|
145
148
|
assertPxTokenMap(cfg.customTextTokens, 'customTextTokens', filename);
|
|
146
149
|
if ('customSpacingTokens' in cfg)
|
|
@@ -176,4 +179,4 @@ export function validateConfig(input, filename = CONFIG_FILENAME) {
|
|
|
176
179
|
}
|
|
177
180
|
return cfg;
|
|
178
181
|
}
|
|
179
|
-
export { loadConfig, resolveInitFilename } from '../io/config.js';
|
|
182
|
+
export { findConfigPath, loadConfig, resolveInitFilename, } from '../io/config.js';
|
|
@@ -2,7 +2,12 @@ import { type ClassStringOpts } from './class-strings.js';
|
|
|
2
2
|
import type { Config } from './rules.js';
|
|
3
3
|
export type FileClasses = {
|
|
4
4
|
file: string;
|
|
5
|
+
/** All class occurrences, used for color and scale statistics. */
|
|
5
6
|
classes: string[];
|
|
7
|
+
/** Individual class strings, used for repeated-pattern detection.
|
|
8
|
+
* When omitted, `classes` is treated as one class string for compatibility.
|
|
9
|
+
*/
|
|
10
|
+
classLists?: string[][];
|
|
6
11
|
};
|
|
7
12
|
export type ColorVariant = {
|
|
8
13
|
token: string;
|
package/dist/core/consistency.js
CHANGED
|
@@ -9,7 +9,11 @@ function parseColor(cls, families, knownColors) {
|
|
|
9
9
|
return null;
|
|
10
10
|
// A known color without an explicit family forms its own family, so colors
|
|
11
11
|
// newly added to the palette are grouped rather than silently dropped.
|
|
12
|
-
const family =
|
|
12
|
+
const family = Object.hasOwn(families, color)
|
|
13
|
+
? families[color]
|
|
14
|
+
: knownColors.has(color)
|
|
15
|
+
? color
|
|
16
|
+
: null;
|
|
13
17
|
if (!family)
|
|
14
18
|
return null;
|
|
15
19
|
return { property, family, token: `${color}-${shade}` };
|
|
@@ -22,7 +26,8 @@ function parseScale(cls, scaleProperties) {
|
|
|
22
26
|
const base = stripVariants(cls);
|
|
23
27
|
const negative = base.startsWith('-');
|
|
24
28
|
const body = negative ? base.slice(1) : base;
|
|
25
|
-
const
|
|
29
|
+
const bracket = body.indexOf('[');
|
|
30
|
+
const dash = body.lastIndexOf('-', bracket === -1 ? body.length : bracket);
|
|
26
31
|
if (dash === -1)
|
|
27
32
|
return null;
|
|
28
33
|
const property = body.slice(0, dash);
|
|
@@ -149,20 +154,22 @@ function detectRareScaleValues(inconsistencies, minPropertyOccurrences, maxFiles
|
|
|
149
154
|
// frequent sub-patterns (no k-subset itemset mining).
|
|
150
155
|
function detectCombinations(input, minSize, minFiles, max) {
|
|
151
156
|
const combos = new Map();
|
|
152
|
-
for (const { file, classes } of input) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
for (const { file, classes: allClasses, classLists } of input) {
|
|
158
|
+
for (const classes of classLists ?? [allClasses]) {
|
|
159
|
+
if (classes.length < minSize)
|
|
160
|
+
continue;
|
|
161
|
+
const unique = [...new Set(classes)].sort();
|
|
162
|
+
if (unique.length < minSize)
|
|
163
|
+
continue;
|
|
164
|
+
const key = unique.join(' ');
|
|
165
|
+
let entry = combos.get(key);
|
|
166
|
+
if (!entry) {
|
|
167
|
+
entry = { classes: unique, count: 0, files: new Set() };
|
|
168
|
+
combos.set(key, entry);
|
|
169
|
+
}
|
|
170
|
+
entry.count++;
|
|
171
|
+
entry.files.add(file);
|
|
163
172
|
}
|
|
164
|
-
entry.count++;
|
|
165
|
-
entry.files.add(file);
|
|
166
173
|
}
|
|
167
174
|
return [...combos.values()]
|
|
168
175
|
.filter((c) => c.files.size >= minFiles)
|
|
@@ -186,6 +186,8 @@ const CORNER_MAP = {
|
|
|
186
186
|
br: ['br'],
|
|
187
187
|
};
|
|
188
188
|
function parseRoundedCorner(cls) {
|
|
189
|
+
if (/^rounded-(?:s|e|ss|se|es|ee)(?:-|$)/.test(cls))
|
|
190
|
+
return null;
|
|
189
191
|
const m = cls.match(/^rounded-(tl|tr|bl|br|t|b|l|r)(?:-(.+))?$/) ??
|
|
190
192
|
cls.match(/^rounded()(?:-(.+))?$/);
|
|
191
193
|
if (!m)
|
|
@@ -321,6 +323,8 @@ function keepLastOf(slots, indices) {
|
|
|
321
323
|
slots[i] = [];
|
|
322
324
|
}
|
|
323
325
|
export function deduplicateClasses(classStr) {
|
|
326
|
+
if (classStr.includes('${'))
|
|
327
|
+
return classStr;
|
|
324
328
|
const original = classStr.split(/\s+/).filter(Boolean);
|
|
325
329
|
if (original.length <= 1)
|
|
326
330
|
return classStr;
|
package/dist/core/merger.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ClassStringOpts } from './class-strings.js';
|
|
2
|
+
export declare function mergeClasses(classes: string, twMerge: (classes: string) => string, opts?: Pick<ClassStringOpts, 'customTextTokens'>): string;
|
|
2
3
|
export declare function mergeContent(content: string, twMerge: (classes: string) => string, opts?: ClassStringOpts): {
|
|
3
4
|
result: string;
|
|
4
5
|
count: number;
|
package/dist/core/merger.js
CHANGED
|
@@ -84,9 +84,12 @@ function restoreLeadingForUnsafeTextSizes(original, merged, customTextClasses) {
|
|
|
84
84
|
}
|
|
85
85
|
return restored.join(' ');
|
|
86
86
|
}
|
|
87
|
-
export function
|
|
87
|
+
export function mergeClasses(classes, twMerge, opts = {}) {
|
|
88
88
|
const customTextClasses = new Set(Object.values(opts.customTextTokens ?? {}).map((token) => `text-${token}`));
|
|
89
|
-
return
|
|
89
|
+
return restoreLeadingForUnsafeTextSizes(classes, twMerge(classes), customTextClasses);
|
|
90
|
+
}
|
|
91
|
+
export function mergeContent(content, twMerge, opts = {}) {
|
|
92
|
+
return replaceClassStrings(content, (classes) => mergeClasses(classes, twMerge, opts), {
|
|
90
93
|
...opts,
|
|
91
94
|
isSuppressed: makeLineSuppressor(content),
|
|
92
95
|
});
|
package/dist/core/rules.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ type DefaultCommandConfig = {
|
|
|
26
26
|
targets?: string[];
|
|
27
27
|
};
|
|
28
28
|
export type Config = {
|
|
29
|
+
/** Set false for custom themes: only explicitly configured px mappings apply. */
|
|
30
|
+
useDefaultTheme?: boolean;
|
|
29
31
|
customTextTokens?: Record<number, string>;
|
|
30
32
|
customSpacingTokens?: Record<number, string>;
|
|
31
33
|
ignorePatterns?: RegExp[];
|
|
@@ -43,5 +45,10 @@ export type Config = {
|
|
|
43
45
|
/** Target Tailwind major. v3 restricts suggestions to its discrete scale. */
|
|
44
46
|
tailwindVersion?: 3 | 4;
|
|
45
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* Suggests the canonical form of a class, preserving its variants
|
|
50
|
+
* (`hover:`, `md:`, `[&:hover]:`), important modifier (`!p-4` / `p-4!`)
|
|
51
|
+
* and sign (`-mt-[8px]` / `mt-[-8px]` → `-mt-2`).
|
|
52
|
+
*/
|
|
46
53
|
export declare function suggestCanonical(cls: string, config?: Config): Suggestion | null;
|
|
47
54
|
export {};
|