Skip to content

Commit 0475e6f

Browse files
authored
feat: suggest installing dependency as devDependency when appropriate (#1052)
1 parent 11c33f2 commit 0475e6f

File tree

14 files changed

+323
-4
lines changed

14 files changed

+323
-4
lines changed

app/components/Terminal/Install.vue

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
<script setup lang="ts">
22
import type { JsrPackageInfo } from '#shared/types/jsr'
3+
import type { DevDependencySuggestion } from '#shared/utils/dev-dependency'
34
import type { PackageManagerId } from '~/utils/install-command'
45
56
const props = defineProps<{
67
packageName: string
78
requestedVersion?: string | null
89
installVersionOverride?: string | null
910
jsrInfo?: JsrPackageInfo | null
11+
devDependencySuggestion?: DevDependencySuggestion | null
1012
typesPackageName?: string | null
1113
executableInfo?: { hasExecutable: boolean; primaryCommand?: string } | null
1214
createPackageInfo?: { packageName: string } | null
@@ -30,6 +32,20 @@ function getInstallPartsForPM(pmId: PackageManagerId) {
3032
})
3133
}
3234
35+
const devDependencySuggestion = computed(
36+
() => props.devDependencySuggestion ?? { recommended: false as const },
37+
)
38+
39+
function getDevInstallPartsForPM(pmId: PackageManagerId) {
40+
return getInstallCommandParts({
41+
packageName: props.packageName,
42+
packageManager: pmId,
43+
version: props.requestedVersion,
44+
jsrInfo: props.jsrInfo,
45+
dev: true,
46+
})
47+
}
48+
3349
// Generate run command parts for a specific package manager
3450
function getRunPartsForPM(pmId: PackageManagerId, command?: string) {
3551
return getRunCommandParts({
@@ -68,7 +84,7 @@ function getTypesInstallPartsForPM(pmId: PackageManagerId) {
6884
const pm = packageManagers.find(p => p.id === pmId)
6985
if (!pm) return []
7086
71-
const devFlag = pmId === 'bun' ? '-d' : '-D'
87+
const devFlag = getDevDependencyFlag(pmId)
7288
const pkgSpec = pmId === 'deno' ? `npm:${props.typesPackageName}` : props.typesPackageName
7389
7490
return [pm.label, pm.action, devFlag, pkgSpec]
@@ -95,6 +111,18 @@ const copyRunCommand = (command?: string) => copyRun(getFullRunCommand(command))
95111
96112
const { copied: createCopied, copy: copyCreate } = useClipboard({ copiedDuring: 2000 })
97113
const copyCreateCommand = () => copyCreate(getFullCreateCommand())
114+
115+
const { copied: devInstallCopied, copy: copyDevInstall } = useClipboard({ copiedDuring: 2000 })
116+
const copyDevInstallCommand = () =>
117+
copyDevInstall(
118+
getInstallCommand({
119+
packageName: props.packageName,
120+
packageManager: selectedPM.value,
121+
version: props.requestedVersion,
122+
jsrInfo: props.jsrInfo,
123+
dev: true,
124+
}),
125+
)
98126
</script>
99127

100128
<template>
@@ -133,6 +161,42 @@ const copyCreateCommand = () => copyCreate(getFullCreateCommand())
133161
</button>
134162
</div>
135163

164+
<!-- Suggested dev dependency install command -->
165+
<template v-if="devDependencySuggestion.recommended">
166+
<div class="flex items-center gap-2 pt-1 select-none">
167+
<span class="text-fg-subtle font-mono text-sm"
168+
># {{ $t('package.get_started.dev_dependency_hint') }}</span
169+
>
170+
</div>
171+
<div
172+
v-for="pm in packageManagers"
173+
:key="`install-dev-${pm.id}`"
174+
:data-pm-cmd="pm.id"
175+
class="flex items-center gap-2 group/devinstallcmd min-w-0"
176+
>
177+
<span class="text-fg-subtle font-mono text-sm select-none shrink-0">$</span>
178+
<code class="font-mono text-sm min-w-0"
179+
><span
180+
v-for="(part, i) in getDevInstallPartsForPM(pm.id)"
181+
:key="i"
182+
:class="i === 0 ? 'text-fg' : 'text-fg-muted'"
183+
>{{ i > 0 ? ' ' : '' }}{{ part }}</span
184+
></code
185+
>
186+
<ButtonBase
187+
type="button"
188+
size="small"
189+
class="text-fg-muted bg-bg-subtle/80 border-border opacity-0 group-hover/devinstallcmd:opacity-100 active:scale-95 focus-visible:opacity-100 select-none"
190+
:aria-label="$t('package.get_started.copy_dev_command')"
191+
@click.stop="copyDevInstallCommand"
192+
>
193+
<span aria-live="polite">{{
194+
devInstallCopied ? $t('common.copied') : $t('common.copy')
195+
}}</span>
196+
</ButtonBase>
197+
</div>
198+
</template>
199+
136200
<!-- @types package install - render all PM variants when types package exists -->
137201
<template v-if="typesPackageName && showTypesInInstall">
138202
<div

app/composables/usePackageAnalysis.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import type { ModuleFormat, TypesStatus, CreatePackageInfo } from '#shared/utils/package-analysis'
2+
import type { DevDependencySuggestion } from '#shared/utils/dev-dependency'
23

34
export interface PackageAnalysisResponse {
45
package: string
56
version: string
67
moduleFormat: ModuleFormat
78
types: TypesStatus
9+
devDependencySuggestion: DevDependencySuggestion
810
engines?: {
911
node?: string
1012
npm?: string

app/pages/package/[[org]]/[name].vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,7 @@ const showSkeleton = shallowRef(false)
12341234
:requested-version="requestedVersion"
12351235
:install-version-override="installVersionOverride"
12361236
:jsr-info="jsrInfo"
1237+
:dev-dependency-suggestion="packageAnalysis?.devDependencySuggestion"
12371238
:types-package-name="typesPackageName"
12381239
:executable-info="executableInfo"
12391240
:create-package-info="createPackageInfo"

app/utils/install-command.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export interface InstallCommandOptions {
6868
packageManager: PackageManagerId
6969
version?: string | null
7070
jsrInfo?: JsrPackageInfo | null
71+
dev?: boolean
72+
}
73+
74+
export function getDevDependencyFlag(packageManager: PackageManagerId): '-D' | '-d' {
75+
return packageManager === 'bun' ? '-d' : '-D'
7176
}
7277

7378
/**
@@ -108,8 +113,9 @@ export function getInstallCommandParts(options: InstallCommandOptions): string[]
108113

109114
const spec = getPackageSpecifier(options)
110115
const version = options.version ? `@${options.version}` : ''
116+
const devFlag = options.dev ? [getDevDependencyFlag(options.packageManager)] : []
111117

112-
return [pm.label, pm.action, `${spec}${version}`]
118+
return [pm.label, pm.action, ...devFlag, `${spec}${version}`]
113119
}
114120

115121
export interface ExecuteCommandOptions extends InstallCommandOptions {

i18n/locales/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@
221221
"title": "Get started",
222222
"pm_label": "Package manager",
223223
"copy_command": "Copy install command",
224+
"copy_dev_command": "Copy dev install command",
225+
"dev_dependency_hint": "Usually installed as a dev dependency",
224226
"view_types": "View {package}"
225227
},
226228
"create": {

i18n/locales/pl-PL.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@
221221
"title": "Zacznij",
222222
"pm_label": "Menedżer pakietów",
223223
"copy_command": "Kopiuj komendę instalacji",
224+
"copy_dev_command": "Kopiuj komendę instalacji dla dev",
225+
"dev_dependency_hint": "Zazwyczaj instalowane jako zależność deweloperska",
224226
"view_types": "Zobacz {package}"
225227
},
226228
"create": {

i18n/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,12 @@
667667
"copy_command": {
668668
"type": "string"
669669
},
670+
"copy_dev_command": {
671+
"type": "string"
672+
},
673+
"dev_dependency_hint": {
674+
"type": "string"
675+
},
670676
"view_types": {
671677
"type": "string"
672678
}

lunaria/files/en-GB.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@
220220
"title": "Get started",
221221
"pm_label": "Package manager",
222222
"copy_command": "Copy install command",
223+
"copy_dev_command": "Copy dev install command",
224+
"dev_dependency_hint": "Usually installed as a dev dependency",
223225
"view_types": "View {package}"
224226
},
225227
"create": {

lunaria/files/en-US.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@
220220
"title": "Get started",
221221
"pm_label": "Package manager",
222222
"copy_command": "Copy install command",
223+
"copy_dev_command": "Copy dev install command",
224+
"dev_dependency_hint": "Usually installed as a dev dependency",
223225
"view_types": "View {package}"
224226
},
225227
"create": {

lunaria/files/pl-PL.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@
220220
"title": "Zacznij",
221221
"pm_label": "Menedżer pakietów",
222222
"copy_command": "Kopiuj komendę instalacji",
223+
"copy_dev_command": "Kopiuj komendę instalacji dla dev",
224+
"dev_dependency_hint": "Zazwyczaj instalowane jako zależność deweloperska",
223225
"view_types": "Zobacz {package}"
224226
},
225227
"create": {

0 commit comments

Comments
 (0)