From dcc48412bd24a5f0303e3eb6a5734d00e4844d74 Mon Sep 17 00:00:00 2001 From: zernonia Date: Tue, 5 Mar 2024 11:46:38 +0800 Subject: [PATCH] feat: add tailwind prefix --- packages/cli/src/utils/get-config.ts | 7 +- packages/cli/src/utils/transformers/index.ts | 2 + .../utils/transformers/transform-tw-prefix.ts | 76 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 packages/cli/src/utils/transformers/transform-tw-prefix.ts diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts index 206fa35e..52b8d182 100644 --- a/packages/cli/src/utils/get-config.ts +++ b/packages/cli/src/utils/get-config.ts @@ -29,6 +29,7 @@ export const rawConfigSchema = z css: z.string(), baseColor: z.string(), cssVariables: z.boolean().default(true), + prefix: z.string().optional(), }), framework: z.string().default('Vite'), aliases: z.object({ @@ -99,9 +100,9 @@ export async function resolveConfigPaths(cwd: string, config: RawConfig) { tailwindCss: path.resolve(cwd, config.tailwind.css), utils: resolveImport(config.aliases.utils, tsConfig), components: resolveImport(config.aliases.components, tsConfig), - ui: config.aliases['ui'] - ? resolveImport(config.aliases['ui'], tsConfig) - : resolveImport(config.aliases['components'], tsConfig), + ui: config.aliases.ui + ? resolveImport(config.aliases.ui, tsConfig) + : resolveImport(config.aliases.components, tsConfig), }, }) } diff --git a/packages/cli/src/utils/transformers/index.ts b/packages/cli/src/utils/transformers/index.ts index e7c52737..0b103bfa 100644 --- a/packages/cli/src/utils/transformers/index.ts +++ b/packages/cli/src/utils/transformers/index.ts @@ -7,6 +7,7 @@ import type { Config } from '@/src/utils/get-config' import type { registryBaseColorSchema } from '@/src/utils/registry/schema' import { transformCssVars } from '@/src/utils/transformers/transform-css-vars' import { transformImport } from '@/src/utils/transformers/transform-import' +import { transformTwPrefixes } from '@/src/utils/transformers/transform-tw-prefix' import { transformSFC } from '@/src/utils/transformers/transform-sfc' export interface TransformOpts { @@ -25,6 +26,7 @@ export type Transformer = ( const transformers: Transformer[] = [ transformCssVars, transformImport, + transformTwPrefixes, ] const project = new Project({ diff --git a/packages/cli/src/utils/transformers/transform-tw-prefix.ts b/packages/cli/src/utils/transformers/transform-tw-prefix.ts new file mode 100644 index 00000000..adaa9766 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-tw-prefix.ts @@ -0,0 +1,76 @@ +import { SyntaxKind } from 'ts-morph' +import { MagicString, parse } from '@vue/compiler-sfc' +import type { SFCTemplateBlock } from '@vue/compiler-sfc' +import { splitClassName } from './transform-css-vars' +import type { Transformer } from '@/src/utils/transformers' + +export const transformTwPrefixes: Transformer = async ({ + sourceFile, + config, +}) => { + const isVueFile = sourceFile.getFilePath().endsWith('vue') + if (!config.tailwind?.prefix) + return sourceFile + + let template: SFCTemplateBlock | null = null + + if (isVueFile) { + const parsed = parse(sourceFile.getText()) + template = parsed.descriptor.template + + if (!template) + return sourceFile + } + + sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral).forEach((node) => { + if (template && template.loc.start.offset >= node.getPos()) + return sourceFile + + const value = node.getText() + const hasClosingDoubleQuote = value.match(/"/g)?.length === 2 + if (value.search('\'') === -1 && hasClosingDoubleQuote) { + const mapped = applyPrefix(value.replace(/"/g, ''), config.tailwind.prefix) + node.replaceWithText(`"${mapped}"`) + } + else { + const s = new MagicString(value) + s.replace(/'(.*?)'/g, (substring) => { + return `'${applyPrefix(substring.replace(/\'/g, ''), config.tailwind.prefix)}'` + }) + node.replaceWithText(s.toString()) + } + }) + + return sourceFile +} + +export function applyPrefix(input: string, prefix: string = '') { + const classNames = input.split(' ') + const prefixed: string[] = [] + for (const className of classNames) { + const [variant, value, modifier] = splitClassName(className) + if (variant) { + modifier + ? prefixed.push(`${variant}:${prefix}${value}/${modifier}`) + : prefixed.push(`${variant}:${prefix}${value}`) + } + else { + modifier + ? prefixed.push(`${prefix}${value}/${modifier}`) + : prefixed.push(`${prefix}${value}`) + } + } + return prefixed.join(' ') +} + +export function applyPrefixesCss(css: string, prefix: string) { + const lines = css.split('\n') + for (const line of lines) { + if (line.includes('@apply')) { + const originalTWCls = line.replace('@apply', '').trim() + const prefixedTwCls = applyPrefix(originalTWCls, prefix) + css = css.replace(originalTWCls, prefixedTwCls) + } + } + return css +}