-
Notifications
You must be signed in to change notification settings - Fork 3
fix: handle scoped npm package aliases SvelteSource.resolveAlias #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,14 +72,27 @@ open class SvelteSource(project: Project) : Source<SvelteConfig>(project, Svelte | |
| fileManager.getFileContentsAtPath(configFileName) | ||
| ?: throw NoSuchFileException("Cannot get $configFileName after sync") | ||
| } | ||
| val aliasPath = parseTsConfig(tsConfig) | ||
| // Handle scoped package aliases (e.g. @repo/ui/components). | ||
| // For @-prefixed aliases, the package name includes a slash (@scope/name), | ||
| // so we split into at most 3 parts to correctly separate the prefix from the rest. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At first glance, splitting with exact numbers feels wonky, CodeRabbit review seems right on the kind of problem that could arise. But to be honest, I'm not really sure what's the best way to handle this: maybe looking at what the original shadcn implementation looks like could help? |
||
| val (aliasPrefix, suffix) = if (alias.startsWith("@")) { | ||
| val parts = alias.split("/", limit = 3) | ||
| val prefix = if (parts.size >= 2) "${parts[0]}/${parts[1]}" else alias | ||
| val rest = if (parts.size >= 3) parts[2] else "" | ||
| prefix to rest | ||
| } else { | ||
| alias.substringBefore("/") to alias.substringAfter("/", "") | ||
| } | ||
|
|
||
| val paths = parseTsConfig(tsConfig) | ||
| .asJsonObject?.get("compilerOptions") | ||
| ?.asJsonObject?.get("paths") | ||
| ?.asJsonObject?.get(alias.substringBefore("/")) | ||
|
|
||
| val aliasPath = (paths?.asJsonObject?.get(aliasPrefix) | ||
| ?: paths?.asJsonObject?.get("$aliasPrefix/*")) | ||
| ?.asJsonArray?.get(0) | ||
| ?.asJsonPrimitive?.content ?: throw Exception("Cannot find alias $alias in $tsConfig") | ||
| val normalized = aliasPath.replace(Regex("^\\.+/"), "") | ||
| val suffix = alias.substringAfter("/", "") | ||
| val normalized = aliasPath.replace(Regex("^\\.+/"), "").removeSuffix("/*") | ||
| val resolved = if (suffix.isEmpty()) normalized else "$normalized/$suffix" | ||
|
Comment on lines
+78
to
96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This regresses single-segment The new branch treats every 🛠️ One way to preserve both scoped and non-scoped forms- val (aliasPrefix, suffix) = if (alias.startsWith("@")) {
- val parts = alias.split("/", limit = 3)
- val prefix = if (parts.size >= 2) "${parts[0]}/${parts[1]}" else alias
- val rest = if (parts.size >= 3) parts[2] else ""
- prefix to rest
- } else {
- alias.substringBefore("/") to alias.substringAfter("/", "")
- }
+ val defaultCandidate = alias.substringBefore("/") to alias.substringAfter("/", "")
+ val scopedCandidate = alias
+ .takeIf { it.startsWith("@") }
+ ?.split("/", limit = 3)
+ ?.takeIf { it.size >= 2 && it[0] != "@" }
+ ?.let { "${it[0]}/${it[1]}" to it.getOrElse(2) { "" } }
val paths = parseTsConfig(tsConfig)
.asJsonObject?.get("compilerOptions")
?.asJsonObject?.get("paths")
- val aliasPath = (paths?.asJsonObject?.get(aliasPrefix)
- ?: paths?.asJsonObject?.get("$aliasPrefix/*"))
- ?.asJsonArray?.get(0)
- ?.asJsonPrimitive?.content ?: throw Exception("Cannot find alias $alias in $tsConfig")
- val normalized = aliasPath.replace(Regex("^\\.+/"), "").removeSuffix("/*")
- val resolved = if (suffix.isEmpty()) normalized else "$normalized/$suffix"
+ fun resolveCandidate(aliasPrefix: String, suffix: String): String? {
+ val aliasPath = (paths?.asJsonObject?.get(aliasPrefix)
+ ?: paths?.asJsonObject?.get("$aliasPrefix/*"))
+ ?.asJsonArray?.get(0)
+ ?.asJsonPrimitive?.content ?: return null
+
+ val normalized = aliasPath.replace(Regex("^\\.+/"), "").removeSuffix("/*")
+ return if (suffix.isEmpty()) normalized else "$normalized/$suffix"
+ }
+
+ val resolved = (scopedCandidate?.let { (aliasPrefix, suffix) ->
+ resolveCandidate(aliasPrefix, suffix)
+ } ?: resolveCandidate(defaultCandidate.first, defaultCandidate.second))
+ ?: throw Exception("Cannot find alias $alias in $tsConfig") |
||
| return resolved.also { log.debug("Resolved alias $alias to $it") } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not particularly a fan of that as the use cases are really rare, but it doesn't hurt either I guess