This commit is contained in:
shadcn
2026-02-26 15:27:34 +04:00
parent d4a2a5fe80
commit 7d4dd65acd
3 changed files with 117 additions and 110 deletions

View File

@@ -2,9 +2,9 @@ import fs from "node:fs/promises"
import path from "node:path"
import * as React from "react"
import { formatCode } from "@/lib/format-code"
import { highlightCode } from "@/lib/highlight-code"
import { getDemoItem, getRegistryItem } from "@/lib/registry"
import { formatCode } from "@/lib/rehype"
import { cn } from "@/lib/utils"
import { CodeCollapsibleWrapper } from "@/components/code-collapsible-wrapper"
import { CopyButton } from "@/components/copy-button"

112
apps/v4/lib/format-code.ts Normal file
View File

@@ -0,0 +1,112 @@
import { promises as fsPromises } from "fs"
import path from "path"
import {
createStyleMap,
transformIcons,
transformMenu,
transformRender,
transformStyle,
} from "shadcn/utils"
import { Project, ScriptKind } from "ts-morph"
import { BASES } from "@/registry/bases"
function getStyleFromStyleName(styleName: string) {
const parts = styleName.split("-")
return parts.length > 1 ? parts.slice(1).join("-") : styleName
}
function buildDisplayConfig(styleName: string) {
return {
$schema: "https://ui.shadcn.com/schema.json",
style: styleName,
rsc: true,
tsx: true,
tailwind: {
config: "",
css: "",
baseColor: "neutral",
cssVariables: true,
prefix: "",
},
iconLibrary: "lucide",
aliases: {
components: "@/components",
utils: "@/lib/utils",
ui: "@/components/ui",
lib: "@/lib",
hooks: "@/hooks",
},
resolvedPaths: {
cwd: "/",
tailwindConfig: "",
tailwindCss: "",
utils: "@/lib/utils",
components: "@/components",
lib: "@/lib",
hooks: "@/hooks",
ui: "@/components/ui",
},
}
}
const styleMapCache = new Map<string, Record<string, string>>()
async function getStyleMap(styleName: string) {
const style = getStyleFromStyleName(styleName)
if (styleMapCache.has(style)) {
return styleMapCache.get(style)!
}
try {
const cssPath = path.join(
process.cwd(),
`registry/styles/style-${style}.css`
)
const css = await fsPromises.readFile(cssPath, "utf-8")
const styleMap = createStyleMap(css)
styleMapCache.set(style, styleMap)
return styleMap
} catch {
return {}
}
}
export async function formatCode(code: string, styleName: string) {
code = code.replaceAll(`@/registry/${styleName}/`, "@/components/")
for (const base of BASES) {
code = code.replaceAll(`@/registry/bases/${base.name}/`, "@/components/")
code = code.replaceAll(`@/examples/${base.name}/ui/`, "@/components/ui/")
code = code.replaceAll(`@/examples/${base.name}/lib/`, "@/lib/")
code = code.replaceAll(`@/examples/${base.name}/hooks/`, "@/hooks/")
}
code = code.replaceAll("export default", "export")
try {
const styleMap = await getStyleMap(styleName)
const transformed = await transformStyle(code, { styleMap })
const config = buildDisplayConfig(styleName)
const project = new Project({ compilerOptions: {} })
const sourceFile = project.createSourceFile("component.tsx", transformed, {
scriptKind: ScriptKind.TSX,
})
const transformers = [transformIcons, transformMenu, transformRender]
for (const transformer of transformers) {
await transformer({
filename: "component.tsx",
raw: transformed,
sourceFile,
config,
})
}
return sourceFile.getText()
} catch (error) {
console.error("Transform failed:", error)
return code
}
}

View File

@@ -1,22 +1,17 @@
import fs, { promises as fsPromises } from "fs"
import fs from "fs"
import path from "path"
import { ExamplesIndex } from "@/examples/__index__"
import {
createStyleMap,
transformIcons,
transformMenu,
transformRender,
transformStyle,
} from "shadcn/utils"
import { Project, ScriptKind } from "ts-morph"
import { u } from "unist-builder"
import { visit } from "unist-util-visit"
import { formatCode } from "@/lib/format-code"
import { Index as StylesIndex } from "@/registry/__index__"
import { getActiveStyle } from "@/registry/_legacy-styles"
import { BASES } from "@/registry/bases"
import { Index as BasesIndex } from "@/registry/bases/__index__"
export { formatCode } from "@/lib/format-code"
function getBaseForStyle(styleName: string) {
for (const base of BASES) {
if (styleName.startsWith(`${base.name}-`)) {
@@ -44,106 +39,6 @@ function getIndexForStyle(styleName: string) {
return { index: StylesIndex, key: styleName }
}
function getStyleFromStyleName(styleName: string) {
const parts = styleName.split("-")
return parts.length > 1 ? parts.slice(1).join("-") : styleName
}
function buildDisplayConfig(styleName: string) {
return {
$schema: "https://ui.shadcn.com/schema.json",
style: styleName,
rsc: true,
tsx: true,
tailwind: {
config: "",
css: "",
baseColor: "neutral",
cssVariables: true,
prefix: "",
},
iconLibrary: "lucide",
aliases: {
components: "@/components",
utils: "@/lib/utils",
ui: "@/components/ui",
lib: "@/lib",
hooks: "@/hooks",
},
resolvedPaths: {
cwd: "/",
tailwindConfig: "",
tailwindCss: "",
utils: "@/lib/utils",
components: "@/components",
lib: "@/lib",
hooks: "@/hooks",
ui: "@/components/ui",
},
}
}
const styleMapCache = new Map<string, Record<string, string>>()
async function getStyleMap(styleName: string) {
const style = getStyleFromStyleName(styleName)
if (styleMapCache.has(style)) {
return styleMapCache.get(style)!
}
try {
const cssPath = path.join(
process.cwd(),
`registry/styles/style-${style}.css`
)
const css = await fsPromises.readFile(cssPath, "utf-8")
const styleMap = createStyleMap(css)
styleMapCache.set(style, styleMap)
return styleMap
} catch {
return {}
}
}
export async function formatCode(code: string, styleName: string) {
code = code.replaceAll(`@/registry/${styleName}/`, "@/components/")
for (const base of BASES) {
code = code.replaceAll(`@/registry/bases/${base.name}/`, "@/components/")
code = code.replaceAll(`@/examples/${base.name}/ui/`, "@/components/ui/")
code = code.replaceAll(`@/examples/${base.name}/lib/`, "@/lib/")
code = code.replaceAll(`@/examples/${base.name}/hooks/`, "@/hooks/")
}
code = code.replaceAll("export default", "export")
try {
const styleMap = await getStyleMap(styleName)
const transformed = await transformStyle(code, { styleMap })
const config = buildDisplayConfig(styleName)
const project = new Project({ compilerOptions: {} })
const sourceFile = project.createSourceFile("component.tsx", transformed, {
scriptKind: ScriptKind.TSX,
})
const transformers = [transformIcons, transformMenu, transformRender]
for (const transformer of transformers) {
await transformer({
filename: "component.tsx",
raw: transformed,
sourceFile,
config,
})
}
return sourceFile.getText()
} catch (error) {
console.error("Transform failed:", error)
return code
}
}
interface UnistNode {
type: string
name?: string