tailwindcss-patch 9.4.1 → 9.4.3

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.
Files changed (34) hide show
  1. package/README.md +69 -0
  2. package/dist/{cli-CBVPia5Z.js → cli-BztQHMRp.js} +63 -64
  3. package/dist/{cli-CgBdW1U5.mjs → cli-D0jXMGXf.mjs} +1 -1
  4. package/dist/cli.js +5 -6
  5. package/dist/cli.mjs +2 -2
  6. package/dist/commands/cli-runtime.d.mts +1 -1
  7. package/dist/commands/cli-runtime.d.ts +1 -1
  8. package/dist/commands/cli-runtime.js +6 -6
  9. package/dist/commands/cli-runtime.mjs +2 -2
  10. package/dist/{dist-B1VBpHtd.js → dist-DDcbvOwe.js} +2 -2
  11. package/dist/index.d.mts +105 -5
  12. package/dist/index.d.ts +105 -5
  13. package/dist/index.js +325 -62
  14. package/dist/index.mjs +253 -4
  15. package/dist/{migrate-config-DqknZpUe.mjs → validate-Bug_WYcU.mjs} +193 -93
  16. package/dist/{validate-CaJv2g5K.d.ts → validate-BuqRodYI.d.ts} +65 -16
  17. package/dist/{migrate-config-Dn9OTXpO.js → validate-DbuKewV-.js} +257 -100
  18. package/dist/{validate-Dr7IkGU8.d.mts → validate-oAkURzUC.d.mts} +65 -15
  19. package/package.json +9 -9
  20. package/src/extraction/candidate-extractor.ts +76 -12
  21. package/src/public-api.ts +54 -13
  22. package/src/style-candidates.ts +35 -0
  23. package/src/style-generator.ts +80 -0
  24. package/src/v3/index.ts +11 -0
  25. package/src/v3/style-generator.ts +384 -0
  26. package/src/v4/bare-arbitrary-values.ts +127 -2
  27. package/src/v4/engine.ts +5 -2
  28. package/src/v4/index.ts +20 -4
  29. package/src/v4/node-adapter.ts +1 -1
  30. package/src/v4/source-scan.ts +1 -1
  31. package/src/v4/style-generator.ts +44 -0
  32. package/src/v4/types.ts +23 -0
  33. package/dist/chunk-8l464Juk.js +0 -28
  34. /package/dist/{dist-BjUV1yEM.mjs → dist-CxmNpfyy.mjs} +0 -0
@@ -1,5 +1,4 @@
1
1
  import { PackageInfo, PackageResolvingOptions } from "local-pkg";
2
- import * as _$consola from "consola";
3
2
  import { Node, Rule } from "postcss";
4
3
  import { CAC, Command } from "cac";
5
4
  import { SourceEntry } from "@tailwindcss/oxide";
@@ -158,6 +157,44 @@ interface PatchStatusReport {
158
157
  entries: PatchStatusEntry[];
159
158
  }
160
159
  //#endregion
160
+ //#region src/v4/bare-arbitrary-values.d.ts
161
+ interface BareArbitraryValueOptions {
162
+ /**
163
+ * 允许作为无方括号任意值的单位列表。
164
+ */
165
+ units?: string[];
166
+ }
167
+ interface BareArbitraryValueResolveResult {
168
+ candidate: string;
169
+ canonicalCandidate: string;
170
+ }
171
+ interface BareArbitraryValueSourceCandidate {
172
+ rawCandidate: string;
173
+ start: number;
174
+ end: number;
175
+ }
176
+ declare function isBareArbitraryValuesEnabled(options: boolean | BareArbitraryValueOptions | undefined): boolean;
177
+ declare function resolveBareArbitraryValueCandidate(candidate: string, options?: boolean | BareArbitraryValueOptions): BareArbitraryValueResolveResult | undefined;
178
+ declare function extractBareArbitraryValueSourceCandidatesWithPositions(content: string, options?: boolean | BareArbitraryValueOptions): BareArbitraryValueSourceCandidate[];
179
+ declare function extractBareArbitraryValueSourceCandidates(content: string, options?: boolean | BareArbitraryValueOptions): string[];
180
+ declare function escapeCssClassName(value: string): string;
181
+ //#endregion
182
+ //#region src/style-candidates.d.ts
183
+ interface TailwindStyleSource {
184
+ content: string;
185
+ extension?: string;
186
+ file?: string;
187
+ }
188
+ interface TailwindStyleCandidateOptions {
189
+ candidates?: Iterable<string>;
190
+ sources?: TailwindStyleSource[];
191
+ /**
192
+ * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`.
193
+ */
194
+ bareArbitraryValues?: boolean | BareArbitraryValueOptions;
195
+ }
196
+ declare function collectTailwindStyleCandidates(options?: TailwindStyleCandidateOptions): Promise<Set<string>>;
197
+ //#endregion
161
198
  //#region src/v4/types.d.ts
162
199
  interface TailwindV4SourceOptions {
163
200
  projectRoot?: string;
@@ -186,6 +223,7 @@ interface TailwindV4CandidateSource {
186
223
  content: string;
187
224
  extension?: string;
188
225
  }
226
+ interface TailwindV4StyleSource extends TailwindStyleSource {}
189
227
  interface TailwindV4GenerateOptions {
190
228
  candidates?: Iterable<string>;
191
229
  sources?: TailwindV4CandidateSource[];
@@ -220,6 +258,23 @@ interface TailwindV4GenerateResult {
220
258
  sources: TailwindV4SourcePattern[];
221
259
  root: TailwindV4CompiledSourceRoot;
222
260
  }
261
+ interface TailwindV4StyleGenerateOptions extends TailwindV4SourceOptions {
262
+ source?: TailwindV4ResolvedSource;
263
+ candidates?: Iterable<string>;
264
+ sources?: TailwindV4StyleSource[];
265
+ /**
266
+ * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`.
267
+ */
268
+ bareArbitraryValues?: TailwindV4GenerateOptions['bareArbitraryValues'];
269
+ /**
270
+ * Scans the compiled Tailwind CSS v4 source entries in addition to in-memory sources.
271
+ */
272
+ scanSources?: TailwindV4GenerateOptions['scanSources'];
273
+ }
274
+ interface TailwindV4StyleGenerateResult extends TailwindV4GenerateResult {
275
+ tokens: Set<string>;
276
+ source: TailwindV4ResolvedSource;
277
+ }
223
278
  interface TailwindV4DesignSystem {
224
279
  parseCandidate: (candidate: string) => unknown[];
225
280
  candidatesToCss: (candidates: string[]) => Array<string | null | undefined>;
@@ -496,14 +551,6 @@ type TailwindcssConfigResult = Awaited<ReturnType<TailwindcssConfigModule['getCo
496
551
  //#region src/runtime/collector.d.ts
497
552
  type TailwindMajorVersion = 2 | 3 | 4;
498
553
  //#endregion
499
- //#region src/v4/bare-arbitrary-values.d.ts
500
- interface BareArbitraryValueOptions {
501
- /**
502
- * 允许作为无方括号任意值的单位列表。
503
- */
504
- units?: string[];
505
- }
506
- //#endregion
507
554
  //#region src/extraction/candidate-extractor.d.ts
508
555
  interface ExtractValidCandidatesOption {
509
556
  sources?: SourceEntry[];
@@ -513,15 +560,18 @@ interface ExtractValidCandidatesOption {
513
560
  cwd?: string;
514
561
  bareArbitraryValues?: boolean | BareArbitraryValueOptions;
515
562
  }
563
+ interface ExtractCandidateOptions {
564
+ bareArbitraryValues?: boolean | BareArbitraryValueOptions;
565
+ }
516
566
  interface ExtractSourceCandidate {
517
567
  rawCandidate: string;
518
568
  start: number;
519
569
  end: number;
520
570
  }
521
- declare function extractRawCandidatesWithPositions(content: string, extension?: string): Promise<ExtractSourceCandidate[]>;
522
- declare function extractSourceCandidatesWithPositions(content: string, extension?: string): Promise<ExtractSourceCandidate[]>;
523
- declare function extractSourceCandidates(content: string, extension?: string): Promise<string[]>;
524
- declare function extractRawCandidates(sources?: SourceEntry[]): Promise<string[]>;
571
+ declare function extractRawCandidatesWithPositions(content: string, extension?: string, options?: ExtractCandidateOptions): Promise<ExtractSourceCandidate[]>;
572
+ declare function extractSourceCandidatesWithPositions(content: string, extension?: string, options?: ExtractCandidateOptions): Promise<ExtractSourceCandidate[]>;
573
+ declare function extractSourceCandidates(content: string, extension?: string, options?: ExtractCandidateOptions): Promise<string[]>;
574
+ declare function extractRawCandidates(sources?: SourceEntry[], options?: ExtractCandidateOptions): Promise<string[]>;
525
575
  declare function extractValidCandidates(options?: ExtractValidCandidatesOption): Promise<string[]>;
526
576
  interface ExtractProjectCandidatesOptions {
527
577
  cwd?: string;
@@ -586,7 +636,7 @@ declare class TailwindcssPatcher {
586
636
  }
587
637
  //#endregion
588
638
  //#region src/logger.d.ts
589
- declare const logger: _$consola.ConsolaInstance;
639
+ declare const logger: import("consola").ConsolaInstance;
590
640
  //#endregion
591
641
  //#region src/commands/migration-report.d.ts
592
642
  declare const MIGRATION_REPORT_KIND = "tw-patch-migrate-report";
@@ -790,4 +840,4 @@ declare class ValidateCommandError extends Error {
790
840
  constructor(summary: ValidateFailureSummary, options?: ErrorOptions);
791
841
  }
792
842
  //#endregion
793
- export { TailwindV4DesignSystem as $, extractSourceCandidates as A, ExposeContextOptions as B, MIGRATION_REPORT_SCHEMA_VERSION as C, CacheContextMetadata as Ct, extractProjectCandidatesWithPositions as D, ExtractSourceCandidate as E, CacheReadResult as Et, BareArbitraryValueOptions as F, TailwindCssOptions as G, ExtractOptions as H, normalizeOptions as I, TailwindV3Options as J, TailwindCssPatchOptions as K, ApplyOptions as L, extractValidCandidates as M, groupTokensByFile as N, extractRawCandidates as O, resolveProjectSourceFiles as P, TailwindV4CssSource as Q, CacheOptions as R, MIGRATION_REPORT_KIND as S, CacheContextDescriptor as St, TailwindcssPatcher as T, CacheReadMeta as Tt, NormalizedCacheOptions as U, ExtendLengthUnitsOptions as V, NormalizedTailwindCssPatchOptions as W, TailwindV4CandidateSource as X, TailwindV4Options as Y, TailwindV4CompiledSourceRoot as Z, ConfigFileMigrationEntry as _, TailwindcssClassCache as _t, ValidateFailureSummary as a, TailwindV4SourcePattern as at, RestoreConfigFilesOptions as b, CacheClearResult as bt, TailwindcssPatchCliMountOptions as c, PatchCheckStatus as ct, TailwindcssPatchCommandContext as d, PatchStatusReport as dt, TailwindV4Engine as et, TailwindcssPatchCommandHandler as f, TailwindPatchRuntime as ft, tailwindcssPatchCommands as g, TailwindTokenReport as gt, TailwindcssPatchCommandOptions as h, TailwindTokenLocation as ht, ValidateFailureReason as i, TailwindV4SourceOptions as it, extractSourceCandidatesWithPositions as j, extractRawCandidatesWithPositions as k, TailwindcssPatchCliOptions as l, PatchName as lt, TailwindcssPatchCommandOptionDefinition as m, TailwindTokenFileKey as mt, VALIDATE_FAILURE_REASONS as n, TailwindV4GenerateResult as nt, ValidateJsonFailurePayload as o, ExtractResult as ot, TailwindcssPatchCommandHandlerMap as p, TailwindTokenByFileMap as pt, TailwindV2Options as q, ValidateCommandError as r, TailwindV4ResolvedSource as rt, ValidateJsonSuccessPayload as s, ILengthUnitsPatchOptions as st, VALIDATE_EXIT_CODES as t, TailwindV4GenerateOptions as tt, TailwindcssPatchCommand as u, PatchStatusEntry as ut, ConfigFileMigrationReport as v, TailwindcssRuntimeContext as vt, logger as w, CacheIndexFileV2 as wt, RestoreConfigFilesResult as x, CacheClearScope as xt, MigrateConfigFilesOptions as y, CacheClearOptions as yt, CacheStrategy as z };
843
+ export { TailwindV4Engine as $, extractSourceCandidates as A, CacheClearOptions as At, ExtendLengthUnitsOptions as B, MIGRATION_REPORT_SCHEMA_VERSION as C, TailwindPatchRuntime as Ct, extractProjectCandidatesWithPositions as D, TailwindTokenReport as Dt, ExtractSourceCandidate as E, TailwindTokenLocation as Et, normalizeOptions as F, CacheIndexFileV2 as Ft, TailwindCssPatchOptions as G, NormalizedCacheOptions as H, ApplyOptions as I, CacheReadMeta as It, TailwindV4Options as J, TailwindV2Options as K, CacheOptions as L, CacheReadResult as Lt, extractValidCandidates as M, CacheClearScope as Mt, groupTokensByFile as N, CacheContextDescriptor as Nt, extractRawCandidates as O, TailwindcssClassCache as Ot, resolveProjectSourceFiles as P, CacheContextMetadata as Pt, TailwindV4DesignSystem as Q, CacheStrategy as R, MIGRATION_REPORT_KIND as S, PatchStatusReport as St, TailwindcssPatcher as T, TailwindTokenFileKey as Tt, NormalizedTailwindCssPatchOptions as U, ExtractOptions as V, TailwindCssOptions as W, TailwindV4CompiledSourceRoot as X, TailwindV4CandidateSource as Y, TailwindV4CssSource as Z, ConfigFileMigrationEntry as _, ExtractResult as _t, ValidateFailureSummary as a, TailwindV4StyleGenerateOptions as at, RestoreConfigFilesOptions as b, PatchName as bt, TailwindcssPatchCliMountOptions as c, TailwindStyleCandidateOptions as ct, TailwindcssPatchCommandContext as d, BareArbitraryValueOptions as dt, TailwindV4GenerateOptions as et, TailwindcssPatchCommandHandler as f, escapeCssClassName as ft, tailwindcssPatchCommands as g, resolveBareArbitraryValueCandidate as gt, TailwindcssPatchCommandOptions as h, isBareArbitraryValuesEnabled as ht, ValidateFailureReason as i, TailwindV4SourcePattern as it, extractSourceCandidatesWithPositions as j, CacheClearResult as jt, extractRawCandidatesWithPositions as k, TailwindcssRuntimeContext as kt, TailwindcssPatchCliOptions as l, TailwindStyleSource as lt, TailwindcssPatchCommandOptionDefinition as m, extractBareArbitraryValueSourceCandidatesWithPositions as mt, VALIDATE_FAILURE_REASONS as n, TailwindV4ResolvedSource as nt, ValidateJsonFailurePayload as o, TailwindV4StyleGenerateResult as ot, TailwindcssPatchCommandHandlerMap as p, extractBareArbitraryValueSourceCandidates as pt, TailwindV3Options as q, ValidateCommandError as r, TailwindV4SourceOptions as rt, ValidateJsonSuccessPayload as s, TailwindV4StyleSource as st, VALIDATE_EXIT_CODES as t, TailwindV4GenerateResult as tt, TailwindcssPatchCommand as u, collectTailwindStyleCandidates as ut, ConfigFileMigrationReport as v, ILengthUnitsPatchOptions as vt, logger as w, TailwindTokenByFileMap as wt, RestoreConfigFilesResult as x, PatchStatusEntry as xt, MigrateConfigFilesOptions as y, PatchCheckStatus as yt, ExposeContextOptions as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tailwindcss-patch",
3
- "version": "9.4.1",
3
+ "version": "9.4.3",
4
4
  "description": "patch tailwindcss for exposing context and extract classes",
5
5
  "author": "ice breaker <1324318532@qq.com>",
6
6
  "license": "MIT",
@@ -61,10 +61,10 @@
61
61
  }
62
62
  },
63
63
  "dependencies": {
64
- "@babel/generator": "^7.29.1",
65
- "@babel/parser": "^7.29.3",
66
- "@babel/traverse": "^7.29.0",
67
- "@babel/types": "^7.29.0",
64
+ "@babel/generator": "^7.29.7",
65
+ "@babel/parser": "^7.29.7",
66
+ "@babel/traverse": "^7.29.7",
67
+ "@babel/types": "^7.29.7",
68
68
  "@tailwindcss/node": "^4.3.0",
69
69
  "@tailwindcss/oxide": "^4.3.0",
70
70
  "cac": "6.7.14",
@@ -74,16 +74,16 @@
74
74
  "micromatch": "^4.0.8",
75
75
  "pathe": "^2.0.3",
76
76
  "postcss": "^8.5.15",
77
- "semver": "^7.8.1",
78
- "tailwindcss-config": "^1.1.5",
77
+ "semver": "^7.8.4",
78
+ "tailwindcss-config": "^2.0.0",
79
79
  "@tailwindcss-mangle/config": "7.0.2"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@tailwindcss/postcss": "^4.3.0",
83
83
  "@tailwindcss/vite": "^4.3.0",
84
- "tailwindcss": "^4.1.18",
84
+ "tailwindcss": "^4.3.0",
85
85
  "tailwindcss-3": "npm:tailwindcss@^3.4.19",
86
- "tailwindcss-4": "npm:tailwindcss@^4.1.18"
86
+ "tailwindcss-4": "npm:tailwindcss@^4.3.0"
87
87
  },
88
88
  "scripts": {
89
89
  "dev": "tsdown --watch --sourcemap",
@@ -5,11 +5,12 @@ import type {
5
5
  TailwindTokenLocation,
6
6
  TailwindTokenReport,
7
7
  } from '../types'
8
+ import type { BareArbitraryValueOptions } from '../v4/bare-arbitrary-values'
8
9
  import { promises as fs } from 'node:fs'
9
10
  import process from 'node:process'
10
11
  import path from 'pathe'
11
12
  import {
12
- type BareArbitraryValueOptions,
13
+ extractBareArbitraryValueSourceCandidatesWithPositions,
13
14
  resolveBareArbitraryValueCandidate,
14
15
  } from '../v4/bare-arbitrary-values'
15
16
  import { extractTailwindV4InlineSourceCandidates, resolveValidTailwindV4Candidates } from '../v4/candidates'
@@ -59,6 +60,10 @@ export interface ExtractValidCandidatesOption {
59
60
  bareArbitraryValues?: boolean | BareArbitraryValueOptions
60
61
  }
61
62
 
63
+ export interface ExtractCandidateOptions {
64
+ bareArbitraryValues?: boolean | BareArbitraryValueOptions
65
+ }
66
+
62
67
  export interface ExtractSourceCandidate {
63
68
  rawCandidate: string
64
69
  start: number
@@ -75,7 +80,7 @@ const HTML_ATTRIBUTE_NAME_CANDIDATE_RE = /^(?:class|className|hover-class|hoverC
75
80
  const CSS_DIRECTIVE_CANDIDATE_RE = /^@(?:apply|tailwind|source|config|plugin|theme|utility|custom-variant|variant)$/
76
81
  const CSS_APPLY_IMPORTANT = '!important'
77
82
  const CSS_APPLY_RE = /@apply\s+([^;{}]+)/g
78
- const JS_LIKE_SOURCE_EXTENSION_RE = /^(?:[cm]?[jt]sx?)$/
83
+ const JS_LIKE_SOURCE_EXTENSION_RE = /^[cm]?[jt]sx?$/
79
84
  const MIXED_TEMPLATE_SOURCE_EXTENSION_RE = /^(?:vue|uvue|nvue|svelte|mpx)$/
80
85
  const CSS_LIKE_SOURCE_EXTENSION_RE = /^(?:css|wxss|acss|jxss|ttss|qss|tyss|scss|sass|less|styl|stylus)$/
81
86
  const SFC_SCRIPT_BLOCK_RE = /<script\b[^>]*>([\s\S]*?)<\/script>/gi
@@ -102,7 +107,7 @@ function isInsideHtmlTagText(content: string, candidate: ExtractSourceCandidate)
102
107
  return false
103
108
  }
104
109
  const nextOpen = content.indexOf('<', candidate.end)
105
- return nextOpen !== -1 && (nextOpen < content.indexOf('>', candidate.end) || content.indexOf('>', candidate.end) === -1)
110
+ return nextOpen !== -1 && (nextOpen < content.indexOf('>', candidate.end) || !content.includes('>', candidate.end))
106
111
  }
107
112
 
108
113
  function isCssDirectiveCandidate(candidate: string) {
@@ -223,7 +228,36 @@ function createLocalCandidate(candidate: ExtractSourceCandidateWithContext): Ext
223
228
  }
224
229
  }
225
230
 
226
- async function extractCssApplyCandidates(content: string, extension: string) {
231
+ function dedupeCandidatesWithPositions(candidates: ExtractSourceCandidate[]) {
232
+ const seen = new Set<string>()
233
+ return candidates.filter((candidate) => {
234
+ const key = `${candidate.start}:${candidate.end}:${candidate.rawCandidate}`
235
+ if (seen.has(key)) {
236
+ return false
237
+ }
238
+ seen.add(key)
239
+ return true
240
+ })
241
+ }
242
+
243
+ function createBareArbitraryValueCandidateContexts(
244
+ content: string,
245
+ extension: string,
246
+ offset: number,
247
+ options?: ExtractCandidateOptions,
248
+ ): ExtractSourceCandidateWithContext[] {
249
+ return extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues)
250
+ .map(candidate => ({
251
+ content,
252
+ extension,
253
+ localStart: candidate.start,
254
+ rawCandidate: candidate.rawCandidate,
255
+ start: candidate.start + offset,
256
+ end: candidate.end + offset,
257
+ }))
258
+ }
259
+
260
+ async function extractCssApplyCandidates(content: string, extension: string, options?: ExtractCandidateOptions) {
227
261
  const candidates: ExtractSourceCandidateWithContext[] = []
228
262
  CSS_APPLY_RE.lastIndex = 0
229
263
  let match = CSS_APPLY_RE.exec(content)
@@ -239,12 +273,13 @@ async function extractCssApplyCandidates(content: string, extension: string) {
239
273
  start: candidate.start + applyParamsStart,
240
274
  end: candidate.end + applyParamsStart,
241
275
  })))
276
+ candidates.push(...createBareArbitraryValueCandidateContexts(applyParams, 'html', applyParamsStart, options))
242
277
  match = CSS_APPLY_RE.exec(content)
243
278
  }
244
279
  return candidates
245
280
  }
246
281
 
247
- async function extractMixedSourceScriptCandidates(content: string) {
282
+ async function extractMixedSourceScriptCandidates(content: string, options?: ExtractCandidateOptions) {
248
283
  const candidates: ExtractSourceCandidateWithContext[] = []
249
284
  SFC_SCRIPT_BLOCK_RE.lastIndex = 0
250
285
  let match = SFC_SCRIPT_BLOCK_RE.exec(content)
@@ -260,6 +295,7 @@ async function extractMixedSourceScriptCandidates(content: string) {
260
295
  start: candidate.start + scriptStart,
261
296
  end: candidate.end + scriptStart,
262
297
  })))
298
+ candidates.push(...createBareArbitraryValueCandidateContexts(scriptContent, 'js', scriptStart, options))
263
299
  match = SFC_SCRIPT_BLOCK_RE.exec(content)
264
300
  }
265
301
  return candidates
@@ -278,26 +314,30 @@ function createCandidateCacheKey(
278
314
  export async function extractRawCandidatesWithPositions(
279
315
  content: string,
280
316
  extension: string = 'html',
317
+ options?: ExtractCandidateOptions,
281
318
  ): Promise<ExtractSourceCandidate[]> {
282
319
  const { Scanner } = await getOxideModule()
283
320
  const scanner = new Scanner({})
284
321
  const result = scanner.getCandidatesWithPositions({ content, extension })
285
322
 
286
- return result.map(({ candidate, position }) => ({
323
+ const candidates = result.map(({ candidate, position }) => ({
287
324
  rawCandidate: candidate,
288
325
  start: position,
289
326
  end: position + candidate.length,
290
327
  }))
328
+ candidates.push(...extractBareArbitraryValueSourceCandidatesWithPositions(content, options?.bareArbitraryValues))
329
+ return dedupeCandidatesWithPositions(candidates)
291
330
  }
292
331
 
293
332
  export async function extractSourceCandidatesWithPositions(
294
333
  content: string,
295
334
  extension: string = 'html',
335
+ options?: ExtractCandidateOptions,
296
336
  ): Promise<ExtractSourceCandidate[]> {
297
337
  const normalizedExtension = extension.replace(/^\./, '')
298
338
  const candidates: ExtractSourceCandidateWithContext[] = CSS_LIKE_SOURCE_EXTENSION_RE.test(normalizedExtension)
299
- ? await extractCssApplyCandidates(content, normalizedExtension)
300
- : (await extractRawCandidatesWithPositions(content, normalizedExtension))
339
+ ? await extractCssApplyCandidates(content, normalizedExtension, options)
340
+ : (await extractRawCandidatesWithPositions(content, normalizedExtension, options))
301
341
  .map(candidate => ({
302
342
  ...candidate,
303
343
  content,
@@ -305,7 +345,7 @@ export async function extractSourceCandidatesWithPositions(
305
345
  localStart: candidate.start,
306
346
  }))
307
347
  if (MIXED_TEMPLATE_SOURCE_EXTENSION_RE.test(normalizedExtension)) {
308
- candidates.push(...await extractMixedSourceScriptCandidates(content))
348
+ candidates.push(...await extractMixedSourceScriptCandidates(content, options))
309
349
  }
310
350
  const seen = new Set<string>()
311
351
  return candidates.filter((candidate) => {
@@ -324,18 +364,37 @@ export async function extractSourceCandidatesWithPositions(
324
364
  export async function extractSourceCandidates(
325
365
  content: string,
326
366
  extension: string = 'html',
367
+ options?: ExtractCandidateOptions,
327
368
  ): Promise<string[]> {
328
- const candidates = await extractSourceCandidatesWithPositions(content, extension)
369
+ const candidates = await extractSourceCandidatesWithPositions(content, extension, options)
329
370
  return [...new Set(candidates.map(candidate => candidate.rawCandidate))]
330
371
  }
331
372
 
332
373
  export async function extractRawCandidates(
333
374
  sources?: SourceEntry[],
375
+ options?: ExtractCandidateOptions,
334
376
  ): Promise<string[]> {
335
377
  const { Scanner } = await getOxideModule()
336
378
  const scanner = new Scanner(sources === undefined ? {} : { sources })
337
379
 
338
- return scanner.scan()
380
+ const candidates = new Set(scanner.scan())
381
+ if (options?.bareArbitraryValues !== undefined && options.bareArbitraryValues !== false) {
382
+ await Promise.all((scanner.files ?? []).map(async (file) => {
383
+ try {
384
+ const content = await fs.readFile(file, 'utf8')
385
+ const extension = toExtension(file)
386
+ for (const candidate of extractBareArbitraryValueSourceCandidatesWithPositions(content, options.bareArbitraryValues)) {
387
+ if (shouldKeepSourceCandidate(content, extension, candidate)) {
388
+ candidates.add(candidate.rawCandidate)
389
+ }
390
+ }
391
+ }
392
+ catch {
393
+ // 文件可能在扫描和读取之间被移除,保持与 Tailwind 原扫描结果一致。
394
+ }
395
+ }))
396
+ }
397
+ return [...candidates]
339
398
  }
340
399
 
341
400
  export async function extractValidCandidates(options?: ExtractValidCandidatesOption) {
@@ -370,7 +429,12 @@ export async function extractValidCandidates(options?: ExtractValidCandidatesOpt
370
429
  const candidateCache = designSystemCandidateCache.get(candidateCacheKey) ?? new Map<string, boolean>()
371
430
  designSystemCandidateCache.set(candidateCacheKey, candidateCache)
372
431
 
373
- const candidates = await extractRawCandidates(sources)
432
+ const candidates = await extractRawCandidates(
433
+ sources,
434
+ providedOptions.bareArbitraryValues === undefined
435
+ ? undefined
436
+ : { bareArbitraryValues: providedOptions.bareArbitraryValues },
437
+ )
374
438
  const inlineSources = extractTailwindV4InlineSourceCandidates(css)
375
439
  for (const candidate of inlineSources.included) {
376
440
  candidates.push(candidate)
package/src/public-api.ts CHANGED
@@ -2,6 +2,17 @@ import type { TailwindcssMangleConfig } from '@tailwindcss-mangle/config'
2
2
 
3
3
  export { TailwindcssPatcher } from './api/tailwindcss-patcher'
4
4
  export { CacheStore } from './cache/store'
5
+ export {
6
+ type ConfigFileMigrationEntry,
7
+ type ConfigFileMigrationReport,
8
+ migrateConfigFiles,
9
+ type MigrateConfigFilesOptions,
10
+ MIGRATION_REPORT_KIND,
11
+ MIGRATION_REPORT_SCHEMA_VERSION,
12
+ restoreConfigFiles,
13
+ type RestoreConfigFilesOptions,
14
+ type RestoreConfigFilesResult,
15
+ } from './commands/migrate-config'
5
16
  export {
6
17
  type TailwindcssPatchCliMountOptions,
7
18
  type TailwindcssPatchCliOptions,
@@ -22,29 +33,18 @@ export {
22
33
  type ValidateJsonFailurePayload,
23
34
  type ValidateJsonSuccessPayload,
24
35
  } from './commands/validate'
25
- export {
26
- type ConfigFileMigrationEntry,
27
- type ConfigFileMigrationReport,
28
- migrateConfigFiles,
29
- type MigrateConfigFilesOptions,
30
- MIGRATION_REPORT_KIND,
31
- MIGRATION_REPORT_SCHEMA_VERSION,
32
- restoreConfigFiles,
33
- type RestoreConfigFilesOptions,
34
- type RestoreConfigFilesResult,
35
- } from './commands/migrate-config'
36
36
  export { normalizeOptions } from './config'
37
37
  export type { TailwindCssPatchOptions } from './config'
38
38
  export {
39
39
  extractProjectCandidatesWithPositions,
40
40
  extractRawCandidates,
41
41
  extractRawCandidatesWithPositions,
42
+ type ExtractSourceCandidate,
42
43
  extractSourceCandidates,
43
44
  extractSourceCandidatesWithPositions,
44
45
  extractValidCandidates,
45
46
  groupTokensByFile,
46
47
  resolveProjectSourceFiles,
47
- type ExtractSourceCandidate,
48
48
  } from './extraction/candidate-extractor'
49
49
  export {
50
50
  isValidCandidateToken,
@@ -59,22 +59,60 @@ export {
59
59
  runTailwindBuild,
60
60
  } from './install'
61
61
  export { default as logger } from './logger'
62
+ export {
63
+ collectTailwindStyleCandidates,
64
+ } from './style-candidates'
65
+ export type {
66
+ TailwindStyleCandidateOptions,
67
+ TailwindStyleSource,
68
+ } from './style-candidates'
69
+ export {
70
+ generateCustomStyle,
71
+ generateTailwindStyle,
72
+ } from './style-generator'
73
+ export type {
74
+ CustomTailwindStyleGenerateContext,
75
+ CustomTailwindStyleGenerateOptions,
76
+ CustomTailwindStyleGenerateResult,
77
+ TailwindStyleGenerateOptions,
78
+ TailwindStyleGenerateResult,
79
+ } from './style-generator'
62
80
  export * from './types'
63
81
  export {
82
+ generateTailwindV3RawStyle,
83
+ generateTailwindV3Style,
84
+ } from './v3'
85
+ export type {
86
+ TailwindV3RawStyleGenerateOptions,
87
+ TailwindV3RawStyleGenerateResult,
88
+ TailwindV3StyleGenerateOptions,
89
+ TailwindV3StyleGenerateResult,
90
+ TailwindV3StyleLayer,
91
+ } from './v3'
92
+ export {
93
+ canonicalizeBareArbitraryValueCandidates,
94
+ collectTailwindV4StyleCandidates,
64
95
  createTailwindV4CompiledSourceEntries,
65
- createTailwindV4Engine,
66
96
  createTailwindV4DefaultIgnoreSources,
97
+ createTailwindV4Engine,
67
98
  createTailwindV4RootSources,
68
99
  createTailwindV4SourceEntryMatcher,
69
100
  createTailwindV4SourceExclusionMatcher,
101
+ escapeCssClassName,
70
102
  expandTailwindV4SourceEntries,
71
103
  expandTailwindV4SourceEntryBraces,
104
+ extractBareArbitraryValueSourceCandidates,
105
+ extractBareArbitraryValueSourceCandidatesWithPositions,
106
+ generateTailwindV4Style,
107
+ isBareArbitraryValuesEnabled,
72
108
  isFileExcludedByTailwindV4SourceEntries,
73
109
  isFileMatchedByTailwindV4SourceEntries,
74
110
  loadTailwindV4DesignSystem,
75
111
  mergeTailwindV4SourceEntries,
76
112
  normalizeTailwindV4ScannerSources,
77
113
  normalizeTailwindV4SourceEntries,
114
+ replaceBareArbitraryValueSelectors,
115
+ resolveBareArbitraryValueCandidate,
78
116
  resolveSourceScanPath,
79
117
  resolveTailwindV4Source,
80
118
  resolveTailwindV4SourceBaseCandidates,
@@ -97,6 +135,9 @@ export type {
97
135
  TailwindV4ResolvedSource,
98
136
  TailwindV4SourceOptions,
99
137
  TailwindV4SourcePattern,
138
+ TailwindV4StyleGenerateOptions,
139
+ TailwindV4StyleGenerateResult,
140
+ TailwindV4StyleSource,
100
141
  } from './v4'
101
142
 
102
143
  export function defineConfig<T extends TailwindcssMangleConfig>(config: T): T {
@@ -0,0 +1,35 @@
1
+ import type { BareArbitraryValueOptions } from './v4/bare-arbitrary-values'
2
+ import { extractSourceCandidates } from './extraction/candidate-extractor'
3
+
4
+ export interface TailwindStyleSource {
5
+ content: string
6
+ extension?: string
7
+ file?: string
8
+ }
9
+
10
+ export interface TailwindStyleCandidateOptions {
11
+ candidates?: Iterable<string>
12
+ sources?: TailwindStyleSource[]
13
+ /**
14
+ * Enables UnoCSS-style bare arbitrary values such as `p-10%` and `p-2.5px`.
15
+ */
16
+ bareArbitraryValues?: boolean | BareArbitraryValueOptions
17
+ }
18
+
19
+ export async function collectTailwindStyleCandidates(
20
+ options: TailwindStyleCandidateOptions = {},
21
+ ): Promise<Set<string>> {
22
+ const candidates = new Set<string>()
23
+ for (const candidate of options.candidates ?? []) {
24
+ candidates.add(candidate)
25
+ }
26
+ for (const source of options.sources ?? []) {
27
+ const sourceCandidates = await extractSourceCandidates(source.content, source.extension, {
28
+ bareArbitraryValues: options.bareArbitraryValues,
29
+ })
30
+ for (const candidate of sourceCandidates) {
31
+ candidates.add(candidate)
32
+ }
33
+ }
34
+ return candidates
35
+ }
@@ -0,0 +1,80 @@
1
+ import type {
2
+ TailwindStyleCandidateOptions,
3
+ TailwindStyleSource,
4
+ } from './style-candidates'
5
+ import type {
6
+ TailwindV3StyleGenerateOptions,
7
+ TailwindV3StyleGenerateResult,
8
+ } from './v3'
9
+ import type {
10
+ TailwindV4StyleGenerateOptions,
11
+ TailwindV4StyleGenerateResult,
12
+ } from './v4'
13
+ import { collectTailwindStyleCandidates } from './style-candidates'
14
+ import { generateTailwindV3Style } from './v3'
15
+ import { generateTailwindV4Style } from './v4'
16
+
17
+ export interface CustomTailwindStyleGenerateContext {
18
+ tokens: Set<string>
19
+ classSet: Set<string>
20
+ sources: TailwindStyleSource[]
21
+ }
22
+
23
+ export interface CustomTailwindStyleGenerateOptions extends TailwindStyleCandidateOptions {
24
+ generate: (context: CustomTailwindStyleGenerateContext) => string | Promise<string>
25
+ }
26
+
27
+ export interface CustomTailwindStyleGenerateResult {
28
+ version: 'custom'
29
+ css: string
30
+ tokens: Set<string>
31
+ classSet: Set<string>
32
+ sources: TailwindStyleSource[]
33
+ }
34
+
35
+ export type TailwindStyleGenerateOptions
36
+ = | ({ version: 3 } & TailwindV3StyleGenerateOptions)
37
+ | ({ version: 4 } & TailwindV4StyleGenerateOptions)
38
+ | ({ version: 'custom' } & CustomTailwindStyleGenerateOptions)
39
+
40
+ export type TailwindStyleGenerateResult
41
+ = | TailwindV3StyleGenerateResult
42
+ | (TailwindV4StyleGenerateResult & { version: 4 })
43
+ | CustomTailwindStyleGenerateResult
44
+
45
+ export async function generateCustomStyle(
46
+ options: CustomTailwindStyleGenerateOptions,
47
+ ): Promise<CustomTailwindStyleGenerateResult> {
48
+ const tokens = await collectTailwindStyleCandidates(options)
49
+ const classSet = new Set(tokens)
50
+ const sources = options.sources ?? []
51
+ const css = await options.generate({
52
+ tokens,
53
+ classSet,
54
+ sources,
55
+ })
56
+
57
+ return {
58
+ version: 'custom',
59
+ css,
60
+ tokens,
61
+ classSet,
62
+ sources,
63
+ }
64
+ }
65
+
66
+ export async function generateTailwindStyle(
67
+ options: TailwindStyleGenerateOptions,
68
+ ): Promise<TailwindStyleGenerateResult> {
69
+ if (options.version === 3) {
70
+ return generateTailwindV3Style(options)
71
+ }
72
+ if (options.version === 4) {
73
+ const result = await generateTailwindV4Style(options)
74
+ return {
75
+ ...result,
76
+ version: 4,
77
+ }
78
+ }
79
+ return generateCustomStyle(options)
80
+ }
@@ -0,0 +1,11 @@
1
+ export {
2
+ generateTailwindV3RawStyle,
3
+ generateTailwindV3Style,
4
+ } from './style-generator'
5
+ export type {
6
+ TailwindV3RawStyleGenerateOptions,
7
+ TailwindV3RawStyleGenerateResult,
8
+ TailwindV3StyleGenerateOptions,
9
+ TailwindV3StyleGenerateResult,
10
+ TailwindV3StyleLayer,
11
+ } from './style-generator'