mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
When migrating a project from Tailwind CSS v3 to Tailwind CSS v4, then we started the migration process in the following order: 1. Migrate the JS/TS config file 2. Migrate the source files (found via the `content` option) 3. Migrate the CSS files However, if you have a setup where you have multiple CSS root files (e.g.: `frontend` and `admin` are separated), then that typically means that you have an `@config` directive in your CSS files. These point to the Tailwind CSS config file. This PR changes the migration order to do the following: 1. Build a tree of all the CSS files 2. For each `@config` directive, migrate the JS/TS config file 3. For each JS/TS config file, migrate the source files If a CSS file does not contain any `@config` directives, then we start by filling in the `@config` directive with the default Tailwind CSS config file (if found, or the one passed in). If no default config file or passed in config file can be found, then we will error out (just like we do now) --------- Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
137 lines
3.3 KiB
TypeScript
137 lines
3.3 KiB
TypeScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import { stripVTControlCharacters } from 'node:util'
|
|
import pc from 'picocolors'
|
|
import { resolve } from '../utils/resolve'
|
|
import { formatNanoseconds } from './format-ns'
|
|
|
|
export const UI = {
|
|
indent: 2,
|
|
}
|
|
export function header() {
|
|
return `${pc.italic(pc.bold(pc.blue('\u2248')))} tailwindcss ${pc.blue(`v${getVersion()}`)}`
|
|
}
|
|
|
|
export function highlight(file: string) {
|
|
return `${pc.dim(pc.blue('`'))}${pc.blue(file)}${pc.dim(pc.blue('`'))}`
|
|
}
|
|
|
|
/**
|
|
* Convert an `absolute` path to a `relative` path from the current working
|
|
* directory.
|
|
*/
|
|
export function relative(
|
|
to: string,
|
|
from = process.cwd(),
|
|
{ preferAbsoluteIfShorter = true } = {},
|
|
) {
|
|
let result = path.relative(from, to)
|
|
if (!result.startsWith('..')) {
|
|
result = `.${path.sep}${result}`
|
|
}
|
|
|
|
if (preferAbsoluteIfShorter && result.length > to.length) {
|
|
return to
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Wrap `text` into multiple lines based on the `width`.
|
|
*/
|
|
export function wordWrap(text: string, width: number): string[] {
|
|
// Handle text with newlines by maintaining the newlines, then splitting
|
|
// each line separately.
|
|
if (text.includes('\n')) {
|
|
return text.split('\n').flatMap((line) => wordWrap(line, width))
|
|
}
|
|
|
|
let words = text.split(' ')
|
|
let lines = []
|
|
|
|
let line = ''
|
|
let lineLength = 0
|
|
for (let word of words) {
|
|
let wordLength = stripVTControlCharacters(word).length
|
|
|
|
if (lineLength + wordLength + 1 > width) {
|
|
lines.push(line)
|
|
line = ''
|
|
lineLength = 0
|
|
}
|
|
|
|
line += (lineLength ? ' ' : '') + word
|
|
lineLength += wordLength + (lineLength ? 1 : 0)
|
|
}
|
|
|
|
if (lineLength) {
|
|
lines.push(line)
|
|
}
|
|
|
|
return lines
|
|
}
|
|
|
|
/**
|
|
* Format a duration in nanoseconds to a more human readable format.
|
|
*/
|
|
export function formatDuration(ns: bigint) {
|
|
let formatted = formatNanoseconds(ns)
|
|
|
|
if (ns <= 50 * 1e6) return pc.green(formatted)
|
|
if (ns <= 300 * 1e6) return pc.blue(formatted)
|
|
if (ns <= 1000 * 1e6) return pc.yellow(formatted)
|
|
|
|
return pc.red(formatted)
|
|
}
|
|
|
|
export function indent(value: string, offset = 0) {
|
|
return `${' '.repeat(offset + UI.indent)}${value}`
|
|
}
|
|
|
|
export function success(message: string, print = eprintln) {
|
|
wordWrap(message, process.stderr.columns - 3).map((line) => {
|
|
return print(`${pc.green('\u2502')} ${line}`)
|
|
})
|
|
print()
|
|
}
|
|
|
|
export function info(message: string, print = eprintln) {
|
|
wordWrap(message, process.stderr.columns - 3).map((line) => {
|
|
return print(`${pc.blue('\u2502')} ${line}`)
|
|
})
|
|
print()
|
|
}
|
|
|
|
export function error(message: string, print = eprintln) {
|
|
wordWrap(message, process.stderr.columns - 3).map((line) => {
|
|
return print(`${pc.red('\u2502')} ${line}`)
|
|
})
|
|
print()
|
|
}
|
|
|
|
export function warn(message: string, print = eprintln) {
|
|
wordWrap(message, process.stderr.columns - 3).map((line) => {
|
|
return print(`${pc.yellow('\u2502')} ${line}`)
|
|
})
|
|
print()
|
|
}
|
|
|
|
// Rust inspired functions to print to the console:
|
|
|
|
export function eprintln(value = '') {
|
|
process.stderr.write(`${value}\n`)
|
|
}
|
|
|
|
export function println(value = '') {
|
|
process.stdout.write(`${value}\n`)
|
|
}
|
|
|
|
function getVersion(): string {
|
|
if (typeof globalThis.__tw_version === 'string') {
|
|
return globalThis.__tw_version
|
|
}
|
|
let { version } = JSON.parse(fs.readFileSync(resolve('tailwindcss/package.json'), 'utf-8'))
|
|
return version
|
|
}
|