55 getPackageSpecifier ,
66 getExecuteCommand ,
77 getExecuteCommandParts ,
8+ getDevDependencySuggestion ,
9+ getDevDependencyFlag ,
810} from '../../../../app/utils/install-command'
911import type { JsrPackageInfo } from '../../../../shared/types/jsr'
1012
@@ -124,6 +126,26 @@ describe('install command generation', () => {
124126 } )
125127 } )
126128
129+ describe ( 'dev dependency installs' , ( ) => {
130+ it . each ( [
131+ [ 'npm' , 'npm install -D eslint' ] ,
132+ [ 'pnpm' , 'pnpm add -D eslint' ] ,
133+ [ 'yarn' , 'yarn add -D eslint' ] ,
134+ [ 'bun' , 'bun add -d eslint' ] ,
135+ [ 'deno' , 'deno add -D npm:eslint' ] ,
136+ [ 'vlt' , 'vlt install -D eslint' ] ,
137+ ] as const ) ( '%s → %s' , ( pm , expected ) => {
138+ expect (
139+ getInstallCommand ( {
140+ packageName : 'eslint' ,
141+ packageManager : pm ,
142+ jsrInfo : jsrNotAvailable ,
143+ dev : true ,
144+ } ) ,
145+ ) . toBe ( expected )
146+ } )
147+ } )
148+
127149 describe ( 'scoped package on JSR without version' , ( ) => {
128150 it . each ( [
129151 [ 'npm' , 'npm install @trpc/server' ] ,
@@ -203,6 +225,16 @@ describe('install command generation', () => {
203225 expect ( parts ) . toEqual ( [ 'npm' , 'install' , 'lodash@4.17.21' ] )
204226 } )
205227
228+ it ( 'returns correct parts for npm with dev flag' , ( ) => {
229+ const parts = getInstallCommandParts ( {
230+ packageName : 'eslint' ,
231+ packageManager : 'npm' ,
232+ jsrInfo : jsrNotAvailable ,
233+ dev : true ,
234+ } )
235+ expect ( parts ) . toEqual ( [ 'npm' , 'install' , '-D' , 'eslint' ] )
236+ } )
237+
206238 it ( 'returns correct parts for deno with jsr: prefix when available' , ( ) => {
207239 const parts = getInstallCommandParts ( {
208240 packageName : '@trpc/server' ,
@@ -212,6 +244,16 @@ describe('install command generation', () => {
212244 expect ( parts ) . toEqual ( [ 'deno' , 'add' , 'jsr:@trpc/server' ] )
213245 } )
214246
247+ it ( 'returns correct parts for bun with lowercase dev flag' , ( ) => {
248+ const parts = getInstallCommandParts ( {
249+ packageName : 'eslint' ,
250+ packageManager : 'bun' ,
251+ jsrInfo : jsrNotAvailable ,
252+ dev : true ,
253+ } )
254+ expect ( parts ) . toEqual ( [ 'bun' , 'add' , '-d' , 'eslint' ] )
255+ } )
256+
215257 it ( 'returns correct parts for deno with npm: prefix when not on JSR' , ( ) => {
216258 const parts = getInstallCommandParts ( {
217259 packageName : 'lodash' ,
@@ -243,6 +285,46 @@ describe('install command generation', () => {
243285 } )
244286 } )
245287
288+ describe ( 'dev dependency suggestion heuristic' , ( ) => {
289+ it ( 'suggests dev dependency for known tooling packages' , ( ) => {
290+ expect ( getDevDependencySuggestion ( 'eslint' ) ) . toEqual ( {
291+ recommended : true ,
292+ reason : 'known-package' ,
293+ } )
294+ expect ( getDevDependencySuggestion ( '@types/node' ) ) . toEqual ( {
295+ recommended : true ,
296+ reason : 'known-package' ,
297+ } )
298+ expect ( getDevDependencySuggestion ( '@typescript-eslint/parser' ) ) . toEqual ( {
299+ recommended : true ,
300+ reason : 'known-package' ,
301+ } )
302+ } )
303+
304+ it ( 'suggests dev dependency from README install command hints' , ( ) => {
305+ const readmeHtml = '<p>Install with <code>npm install --save-dev some-tool</code></p>'
306+
307+ expect ( getDevDependencySuggestion ( 'some-tool' , readmeHtml ) ) . toEqual ( {
308+ recommended : true ,
309+ reason : 'readme-hint' ,
310+ } )
311+ } )
312+
313+ it ( 'does not suggest dev dependency for runtime packages without hints' , ( ) => {
314+ expect ( getDevDependencySuggestion ( 'react' ) ) . toEqual ( {
315+ recommended : false ,
316+ } )
317+ } )
318+ } )
319+
320+ describe ( 'getDevDependencyFlag' , ( ) => {
321+ it ( 'returns lowercase flag only for bun' , ( ) => {
322+ expect ( getDevDependencyFlag ( 'bun' ) ) . toBe ( '-d' )
323+ expect ( getDevDependencyFlag ( 'npm' ) ) . toBe ( '-D' )
324+ expect ( getDevDependencyFlag ( 'deno' ) ) . toBe ( '-D' )
325+ } )
326+ } )
327+
246328 describe ( 'edge cases' , ( ) => {
247329 it ( 'handles null jsrInfo same as not available for deno' , ( ) => {
248330 expect (
0 commit comments