@@ -125,12 +125,43 @@ describe('CLI Path Utilities', () => {
125125 } ) ;
126126 } ) ;
127127
128- it ( 'should throw for invalid runtime prefix format' , ( ) => {
128+ it ( 'should treat non-whitelisted runtime prefixes as command names' , ( ) => {
129+ // With whitelist approach, 'invalid:format' is not recognized as a runtime spec
130+ // so it's treated as a command name, which fails validation due to the colon
129131 expect ( ( ) => parseExecutableSpec ( 'invalid:format' ) ) . toThrow (
130- 'Unsupported runtime ' ,
132+ 'Invalid command name ' ,
131133 ) ;
132134 } ) ;
133135
136+ it ( 'should treat Windows drive letters as file paths, not runtime specs' , ( ) => {
137+ mockFs . existsSync . mockReturnValue ( true ) ;
138+
139+ // Test various Windows drive letters
140+ const windowsPaths = [
141+ 'C:\\path\\to\\cli.js' ,
142+ 'D:\\path\\to\\cli.js' ,
143+ 'E:\\Users\\dev\\qwen\\cli.js' ,
144+ ] ;
145+
146+ for ( const winPath of windowsPaths ) {
147+ const result = parseExecutableSpec ( winPath ) ;
148+
149+ expect ( result . isExplicitRuntime ) . toBe ( false ) ;
150+ expect ( result . runtime ) . toBeUndefined ( ) ;
151+ expect ( result . executablePath ) . toBe ( path . resolve ( winPath ) ) ;
152+ }
153+ } ) ;
154+
155+ it ( 'should handle Windows paths with forward slashes' , ( ) => {
156+ mockFs . existsSync . mockReturnValue ( true ) ;
157+
158+ const result = parseExecutableSpec ( 'C:/path/to/cli.js' ) ;
159+
160+ expect ( result . isExplicitRuntime ) . toBe ( false ) ;
161+ expect ( result . runtime ) . toBeUndefined ( ) ;
162+ expect ( result . executablePath ) . toBe ( path . resolve ( 'C:/path/to/cli.js' ) ) ;
163+ } ) ;
164+
134165 it ( 'should throw when runtime-prefixed file does not exist' , ( ) => {
135166 mockFs . existsSync . mockReturnValue ( false ) ;
136167
@@ -453,6 +484,41 @@ describe('CLI Path Utilities', () => {
453484 originalInput : `bun:${ bundlePath } ` ,
454485 } ) ;
455486 } ) ;
487+
488+ it ( 'should handle Windows paths with drive letters' , ( ) => {
489+ const windowsPath = 'D:\\path\\to\\cli.js' ;
490+ const result = prepareSpawnInfo ( windowsPath ) ;
491+
492+ expect ( result ) . toEqual ( {
493+ command : process . execPath ,
494+ args : [ path . resolve ( windowsPath ) ] ,
495+ type : 'node' ,
496+ originalInput : windowsPath ,
497+ } ) ;
498+ } ) ;
499+
500+ it ( 'should handle Windows paths with TypeScript files' , ( ) => {
501+ const windowsPath = 'C:\\Users\\dev\\qwen\\index.ts' ;
502+ const result = prepareSpawnInfo ( windowsPath ) ;
503+
504+ expect ( result ) . toEqual ( {
505+ command : 'tsx' ,
506+ args : [ path . resolve ( windowsPath ) ] ,
507+ type : 'tsx' ,
508+ originalInput : windowsPath ,
509+ } ) ;
510+ } ) ;
511+
512+ it ( 'should not confuse Windows drive letters with runtime prefixes' , ( ) => {
513+ // Ensure 'D:' is not treated as a runtime specification
514+ const windowsPath = 'D:\\workspace\\project\\cli.js' ;
515+ const result = prepareSpawnInfo ( windowsPath ) ;
516+
517+ // Should use node runtime based on .js extension, not treat 'D' as runtime
518+ expect ( result . type ) . toBe ( 'node' ) ;
519+ expect ( result . command ) . toBe ( process . execPath ) ;
520+ expect ( result . args ) . toEqual ( [ path . resolve ( windowsPath ) ] ) ;
521+ } ) ;
456522 } ) ;
457523
458524 describe ( 'error cases' , ( ) => {
@@ -472,21 +538,39 @@ describe('CLI Path Utilities', () => {
472538 ) ;
473539 } ) ;
474540
475- it ( 'should provide helpful error for invalid runtime specification' , ( ) => {
541+ it ( 'should treat non-whitelisted runtime prefixes as command names' , ( ) => {
542+ // With whitelist approach, 'invalid:spec' is not recognized as a runtime spec
543+ // so it's treated as a command name, which fails validation due to the colon
476544 expect ( ( ) => prepareSpawnInfo ( 'invalid:spec' ) ) . toThrow (
477- 'Unsupported runtime' ,
545+ 'Invalid command name' ,
546+ ) ;
547+ } ) ;
548+
549+ it ( 'should handle Windows paths correctly even when file is missing' , ( ) => {
550+ mockFs . existsSync . mockReturnValue ( false ) ;
551+
552+ expect ( ( ) => prepareSpawnInfo ( 'D:\\missing\\cli.js' ) ) . toThrow (
553+ 'Executable file not found at' ,
554+ ) ;
555+ // Should not throw 'Invalid command name' error (which would happen if 'D:' was treated as invalid command)
556+ expect ( ( ) => prepareSpawnInfo ( 'D:\\missing\\cli.js' ) ) . not . toThrow (
557+ 'Invalid command name' ,
478558 ) ;
479559 } ) ;
480560 } ) ;
481561
482562 describe ( 'comprehensive validation' , ( ) => {
483563 describe ( 'runtime validation' , ( ) => {
484- it ( 'should reject unsupported runtimes' , ( ) => {
485- expect ( ( ) =>
486- parseExecutableSpec ( 'unsupported:/path/to/file.js' ) ,
487- ) . toThrow (
488- "Unsupported runtime 'unsupported'. Supported runtimes: node, bun, tsx, deno" ,
489- ) ;
564+ it ( 'should treat unsupported runtime prefixes as file paths' , ( ) => {
565+ mockFs . existsSync . mockReturnValue ( true ) ;
566+
567+ // With whitelist approach, 'unsupported:' is not recognized as a runtime spec
568+ // so 'unsupported:/path/to/file.js' is treated as a file path
569+ const result = parseExecutableSpec ( 'unsupported:/path/to/file.js' ) ;
570+
571+ // Should be treated as a file path, not a runtime specification
572+ expect ( result . isExplicitRuntime ) . toBe ( false ) ;
573+ expect ( result . runtime ) . toBeUndefined ( ) ;
490574 } ) ;
491575
492576 it ( 'should validate runtime availability for explicit runtime specs' , ( ) => {
0 commit comments