mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-25 13:46:07 +00:00
fix: refactor
This commit is contained in:
@@ -7,10 +7,7 @@ import {
|
||||
} from "@/src/schema"
|
||||
import { getProjectInfo } from "@/src/utils/get-project-info"
|
||||
import { highlighter } from "@/src/utils/highlighter"
|
||||
import {
|
||||
resolveImport,
|
||||
resolveImportWithMetadata,
|
||||
} from "@/src/utils/resolve-import"
|
||||
import { resolveImportWithMetadata } from "@/src/utils/resolve-import"
|
||||
import { cosmiconfig } from "cosmiconfig"
|
||||
import fg from "fast-glob"
|
||||
import { loadConfig, type ConfigLoaderSuccessResult } from "tsconfig-paths"
|
||||
@@ -67,6 +64,20 @@ export async function resolveConfigPaths(
|
||||
)
|
||||
}
|
||||
|
||||
// Resolve the primary aliases first so fallbacks can reuse their results.
|
||||
const resolvedUtils = await resolveAliasPath(
|
||||
"utils",
|
||||
config.aliases["utils"],
|
||||
cwd,
|
||||
tsConfig
|
||||
)
|
||||
const resolvedComponents = await resolveAliasPath(
|
||||
"components",
|
||||
config.aliases["components"],
|
||||
cwd,
|
||||
tsConfig
|
||||
)
|
||||
|
||||
return configSchema.parse({
|
||||
...config,
|
||||
resolvedPaths: {
|
||||
@@ -75,42 +86,16 @@ export async function resolveConfigPaths(
|
||||
? path.resolve(cwd, config.tailwind.config)
|
||||
: "",
|
||||
tailwindCss: path.resolve(cwd, config.tailwind.css),
|
||||
utils: await resolveAliasPath(
|
||||
"utils",
|
||||
config.aliases["utils"],
|
||||
cwd,
|
||||
tsConfig
|
||||
),
|
||||
components: await resolveAliasPath(
|
||||
"components",
|
||||
config.aliases["components"],
|
||||
cwd,
|
||||
tsConfig
|
||||
),
|
||||
utils: resolvedUtils,
|
||||
components: resolvedComponents,
|
||||
ui: config.aliases["ui"]
|
||||
? await resolveAliasPath("ui", config.aliases["ui"], cwd, tsConfig)
|
||||
: path.resolve(
|
||||
(await resolveAliasPath(
|
||||
"components",
|
||||
config.aliases["components"],
|
||||
cwd,
|
||||
tsConfig
|
||||
)) ?? cwd,
|
||||
"ui"
|
||||
),
|
||||
: path.resolve(resolvedComponents ?? cwd, "ui"),
|
||||
// TODO: Make this configurable.
|
||||
// For now, we assume the lib and hooks directories are one level up from the components directory.
|
||||
lib: config.aliases["lib"]
|
||||
? await resolveAliasPath("lib", config.aliases["lib"], cwd, tsConfig)
|
||||
: path.resolve(
|
||||
(await resolveAliasPath(
|
||||
"utils",
|
||||
config.aliases["utils"],
|
||||
cwd,
|
||||
tsConfig
|
||||
)) ?? cwd,
|
||||
".."
|
||||
),
|
||||
: path.resolve(resolvedUtils ?? cwd, ".."),
|
||||
hooks: config.aliases["hooks"]
|
||||
? await resolveAliasPath(
|
||||
"hooks",
|
||||
@@ -118,16 +103,7 @@ export async function resolveConfigPaths(
|
||||
cwd,
|
||||
tsConfig
|
||||
)
|
||||
: path.resolve(
|
||||
(await resolveAliasPath(
|
||||
"components",
|
||||
config.aliases["components"],
|
||||
cwd,
|
||||
tsConfig
|
||||
)) ?? cwd,
|
||||
"..",
|
||||
"hooks"
|
||||
),
|
||||
: path.resolve(resolvedComponents ?? cwd, "..", "hooks"),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -144,36 +120,32 @@ async function resolveAliasPath(
|
||||
})
|
||||
|
||||
if (!resolved?.path) {
|
||||
return await resolveImport(alias, { ...tsConfig, cwd })
|
||||
return null
|
||||
}
|
||||
|
||||
// For non-utils alias keys backed by package imports or workspace exports,
|
||||
// strip directory-level artifacts so the resolved path points at the
|
||||
// directory root rather than a specific file.
|
||||
if (
|
||||
aliasKey !== "utils" &&
|
||||
["package_imports", "workspace_package_exports"].includes(
|
||||
resolved.source
|
||||
) &&
|
||||
!resolved.matchedAlias.includes("*") &&
|
||||
/\/index\.[^/]+$/.test(resolved.path)
|
||||
(resolved.source === "package_imports" ||
|
||||
resolved.source === "workspace_package_exports")
|
||||
) {
|
||||
// Exact package-import aliases like `#hooks`, and exact workspace package
|
||||
// exports that point at index files, should resolve to directory roots for
|
||||
// components/hooks/ui/lib. `utils` stays file-based by design.
|
||||
return path.dirname(resolved.path)
|
||||
}
|
||||
// Exact aliases (e.g. `#hooks` → `./src/hooks/index.ts`) should resolve
|
||||
// to the directory root.
|
||||
if (
|
||||
!resolved.matchedAlias.includes("*") &&
|
||||
/\/index\.[^/]+$/.test(resolved.path)
|
||||
) {
|
||||
return path.dirname(resolved.path)
|
||||
}
|
||||
|
||||
if (
|
||||
aliasKey !== "utils" &&
|
||||
["package_imports", "workspace_package_exports"].includes(
|
||||
resolved.source
|
||||
) &&
|
||||
resolved.matchedAlias.includes("*") &&
|
||||
/\.[^/]+$/.test(resolved.path)
|
||||
) {
|
||||
// Wildcard package-import aliases and workspace package exports stored in
|
||||
// components.json represent directory roots, even when the matched target
|
||||
// is extension-based (`./src/components/*.tsx`). Strip the source extension
|
||||
// so `ui` resolves to `/src/components/ui` instead of `/src/components/ui.tsx`.
|
||||
return resolved.path.replace(/\.[^/]+$/, "")
|
||||
// Wildcard aliases with explicit extensions (e.g. `#components/*` →
|
||||
// `./src/components/*.tsx`) should strip the source extension so `ui`
|
||||
// resolves to `/src/components/ui` instead of `/src/components/ui.tsx`.
|
||||
if (resolved.matchedAlias.includes("*") && /\.[^/]+$/.test(resolved.path)) {
|
||||
return resolved.path.replace(/\.[^/]+$/, "")
|
||||
}
|
||||
}
|
||||
|
||||
return resolved.path
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getPatternWildcardValue } from "@/src/utils/import-matcher"
|
||||
import {
|
||||
resolvePackageImport,
|
||||
type ImportEmitMode,
|
||||
@@ -119,7 +120,7 @@ function findMatchingTsPathPattern(
|
||||
) {
|
||||
for (const [key, targets] of Object.entries(paths)) {
|
||||
const targetList = Array.isArray(targets) ? targets : [targets]
|
||||
const wildcardValue = getWildcardValue(importPath, key)
|
||||
const wildcardValue = getPatternWildcardValue(importPath, key)
|
||||
|
||||
if (wildcardValue === null) {
|
||||
continue
|
||||
@@ -136,18 +137,3 @@ function findMatchingTsPathPattern(
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function getWildcardValue(importPath: string, pattern: string) {
|
||||
if (!pattern.includes("*")) {
|
||||
return importPath === pattern ? "" : null
|
||||
}
|
||||
|
||||
const [prefix, suffix = ""] = pattern.split("*")
|
||||
if (!importPath.startsWith(prefix) || !importPath.endsWith(suffix)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return suffix
|
||||
? importPath.slice(prefix.length, -suffix.length)
|
||||
: importPath.slice(prefix.length)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ import { Project, ScriptKind } from "ts-morph"
|
||||
import { loadConfig, type ConfigLoaderSuccessResult } from "tsconfig-paths"
|
||||
import { z } from "zod"
|
||||
|
||||
const CODE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"]
|
||||
|
||||
export async function updateFiles(
|
||||
files: RegistryItem["files"],
|
||||
config: Config,
|
||||
@@ -868,8 +870,7 @@ export function toAliasedImport(
|
||||
|
||||
// 3️⃣ Strip code-file extensions, keep others (css, json, etc.)
|
||||
const ext = path.posix.extname(rel)
|
||||
const codeExts = [".ts", ".tsx", ".js", ".jsx"]
|
||||
const keepExt = codeExts.includes(ext) ? "" : ext
|
||||
const keepExt = CODE_EXTENSIONS.includes(ext) ? "" : ext
|
||||
let noExt = rel.slice(0, rel.length - ext.length)
|
||||
|
||||
// 4️⃣ Collapse "/index" to its directory
|
||||
@@ -895,9 +896,9 @@ function toPackageImport(
|
||||
: never
|
||||
) {
|
||||
const ext = path.posix.extname(relativePath)
|
||||
const codeExts = [".ts", ".tsx", ".js", ".jsx"]
|
||||
const keepExt =
|
||||
codeExts.includes(ext) && packageImport.emitMode === "strip_extension"
|
||||
CODE_EXTENSIONS.includes(ext) &&
|
||||
packageImport.emitMode === "strip_extension"
|
||||
? ""
|
||||
: ext
|
||||
const normalizedRelativePath = relativePath
|
||||
@@ -996,8 +997,7 @@ function toRelativeImport(fromFilePath: string, targetFilePath: string) {
|
||||
rel = rel.split(path.sep).join("/")
|
||||
|
||||
const ext = path.posix.extname(rel)
|
||||
const codeExts = [".ts", ".tsx", ".js", ".jsx"]
|
||||
const keepExt = codeExts.includes(ext) ? "" : ext
|
||||
const keepExt = CODE_EXTENSIONS.includes(ext) ? "" : ext
|
||||
let noExt = rel.slice(0, rel.length - ext.length)
|
||||
|
||||
if (noExt.endsWith("/index")) {
|
||||
|
||||
Reference in New Issue
Block a user