1- var npa = require ( '../npa.js' )
2- var path = require ( 'path' )
3- var os = require ( 'os' )
1+ const path = require ( 'path' ) . posix
2+ const os = require ( 'os' )
43
54const normalizePath = p => p && p . replace ( / ^ [ a - z A - Z ] : / , '' ) . replace ( / \\ / g, '/' )
65
6+ const cwd = normalizePath ( process . cwd ( ) )
7+ process . cwd = ( ) => cwd
78const normalizePaths = spec => {
89 spec . saveSpec = normalizePath ( spec . saveSpec )
910 spec . fetchSpec = normalizePath ( spec . fetchSpec )
1011 return spec
1112}
1213
13- require ( 'tap' ) . test ( 'basic' , function ( t ) {
14+ const t = require ( 'tap' )
15+ const npa = t . mock ( '../npa.js' , { path } )
16+ t . on ( 'bailout' , ( ) => process . exit ( 1 ) )
17+
18+ t . test ( 'basic' , function ( t ) {
1419 t . setMaxListeners ( 999 )
1520
16- var tests = {
21+ const tests = {
1722 'foo@1.2' : {
1823 name : 'foo' ,
1924 escapedName : 'foo' ,
@@ -472,6 +477,14 @@ require('tap').test('basic', function (t) {
472477 raw : 'file:////path/to/foo' ,
473478 } ,
474479
480+ 'file://.' : {
481+ name : null ,
482+ escapedName : null ,
483+ type : 'directory' ,
484+ saveSpec : 'file:' ,
485+ raw : 'file://.' ,
486+ } ,
487+
475488 'http://insecure.com/foo.tgz' : {
476489 name : null ,
477490 escapedName : null ,
@@ -550,14 +563,14 @@ require('tap').test('basic', function (t) {
550563 }
551564
552565 Object . keys ( tests ) . forEach ( function ( arg ) {
553- var res = normalizePaths ( npa ( arg , '/test/a/b' ) )
566+ const res = normalizePaths ( npa ( arg , '/test/a/b' ) )
554567 t . ok ( res instanceof npa . Result , arg + ' is a result' )
555568 Object . keys ( tests [ arg ] ) . forEach ( function ( key ) {
556569 t . match ( res [ key ] , tests [ arg ] [ key ] , arg + ' [' + key + ']' )
557570 } )
558571 } )
559572
560- var objSpec = { name : 'foo' , rawSpec : '1.2.3' }
573+ let objSpec = { name : 'foo' , rawSpec : '1.2.3' }
561574 t . equal ( npa ( objSpec , '/whatnot' ) . toString ( ) , 'foo@1.2.3' , 'parsed object' )
562575
563576 objSpec . where = '/whatnot'
@@ -569,19 +582,23 @@ require('tap').test('basic', function (t) {
569582 objSpec = { raw : './foo/bar' , where : '/here' }
570583 t . equal ( normalizePath ( npa ( objSpec ) . fetchSpec ) , '/here/foo/bar' , '`where` is reused' )
571584
572- var res = new npa . Result ( { name : 'bar' , rawSpec : './foo/bar' } )
585+ let res = new npa . Result ( { name : 'bar' , rawSpec : './foo/bar' } )
573586 t . equal ( res . toString ( ) , 'bar@./foo/bar' , 'toString with only rawSpec' )
574587 res = new npa . Result ( { rawSpec : './x/y' } )
575588 t . equal ( normalizePath ( res . toString ( ) ) , './x/y' , 'toString with only rawSpec, no name' )
576589 res = new npa . Result ( { rawSpec : '' } )
577590 t . equal ( res . toString ( ) , '' , 'toString with nothing' )
578591
579592 objSpec = { raw : './foo/bar' , where : '/here' }
580- t . equal ( normalizePath ( npa ( objSpec , '/whatnot' ) . fetchSpec ) , '/whatnot/foo/bar' , '`where` arg overrides the one in the spec object' )
593+ t . equal (
594+ normalizePath ( npa ( objSpec , '/whatnot' ) . fetchSpec ) ,
595+ '/whatnot/foo/bar' ,
596+ '`where` arg overrides the one in the spec object'
597+ )
581598
582599 t . equal ( npa ( npa ( 'foo@1.2.3' ) ) . toString ( ) , 'foo@1.2.3' , 'spec is passthrough' )
583600
584- var parsedSpec = npa ( './foo' , './here' )
601+ const parsedSpec = npa ( './foo' , './here' )
585602 t . equal ( npa ( parsedSpec ) , parsedSpec , 'reused if no where' )
586603 t . equal ( npa ( parsedSpec , './here' ) , parsedSpec , 'reused if where matches' )
587604 t . not ( npa ( parsedSpec , './there' ) , parsedSpec , 'new instance if where does not match' )
@@ -607,14 +624,72 @@ require('tap').test('basic', function (t) {
607624 npa ( 'foo@npm:foo/bar' )
608625 } , 'aliases only work for registry deps' )
609626
610- t . has ( npa . resolve ( 'foo' , '^1.2.3' , '/test/a/b' ) , { type : 'range' } , 'npa.resolve' )
611- t . has ( normalizePaths ( npa . resolve ( 'foo' , 'file:foo' , '/test/a/b' ) ) , { type : 'directory' , fetchSpec : '/test/a/b/foo' } , 'npa.resolve file:' )
612- t . has ( npa . resolve ( 'foo' , '../foo/bar' , '/test/a/b' ) , { type : 'directory' } , 'npa.resolve no protocol' )
613- t . has ( npa . resolve ( 'foo' , 'file:../foo/bar' , '/test/a/b' ) , { type : 'directory' } , 'npa.resolve file protocol' )
614- t . has ( npa . resolve ( 'foo' , 'file:../foo/bar.tgz' , '/test/a/b' ) , { type : 'file' } , 'npa.resolve file protocol w/ tgz' )
615- t . has ( npa . resolve ( null , '4.0.0' , '/test/a/b' ) , { type : 'version' , name : null } , 'npa.resolve with no name' )
616- t . has ( npa . resolve ( 'foo' , 'file:abc' ) , { type : 'directory' , raw : 'foo@file:abc' } , 'npa.resolve sets raw right' )
617- t . has ( npa ( './path/to/thing/package@1.2.3/' ) , { name : null , type : 'directory' } , 'npa with path in @ in it' )
618- t . has ( npa ( 'path/to/thing/package@1.2.3' ) , { name : null , type : 'directory' } , 'npa w/o leading or trailing slash' )
627+ t . has ( npa . resolve ( 'foo' , '^1.2.3' , '/test/a/b' ) , {
628+ type : 'range' ,
629+ } , 'npa.resolve' )
630+ t . has ( normalizePaths ( npa . resolve ( 'foo' , 'file:foo' , '/test/a/b' ) ) , {
631+ type : 'directory' ,
632+ fetchSpec : '/test/a/b/foo' ,
633+ } , 'npa.resolve file:' )
634+ t . has ( npa . resolve ( 'foo' , '../foo/bar' , '/test/a/b' ) , {
635+ type : 'directory' ,
636+ } , 'npa.resolve no protocol' )
637+ t . has ( npa . resolve ( 'foo' , 'file:../foo/bar' , '/test/a/b' ) , {
638+ type : 'directory' ,
639+ } , 'npa.resolve file protocol' )
640+ t . has ( npa . resolve ( 'foo' , 'file:../foo/bar.tgz' , '/test/a/b' ) , {
641+ type : 'file' ,
642+ } , 'npa.resolve file protocol w/ tgz' )
643+ t . has ( npa . resolve ( null , '4.0.0' , '/test/a/b' ) , {
644+ type : 'version' ,
645+ name : null ,
646+ } , 'npa.resolve with no name' )
647+ t . has ( npa . resolve ( 'foo' , 'file:abc' ) , {
648+ type : 'directory' ,
649+ raw : 'foo@file:abc' ,
650+ } , 'npa.resolve sets raw right' )
651+ t . has ( npa ( './path/to/thing/package@1.2.3/' ) , {
652+ name : null ,
653+ type : 'directory' ,
654+ } , 'npa with path in @ in it' )
655+ t . has ( npa ( 'path/to/thing/package@1.2.3' ) , {
656+ name : null ,
657+ type : 'directory' ,
658+ } , 'npa w/o leading or trailing slash' )
659+ t . end ( )
660+ } )
661+
662+ t . test ( 'strict 8909 compliance mode' , t => {
663+ t . teardown ( ( ) => process . env . NPM_PACKAGE_ARG_8909_STRICT = '0' )
664+ process . env . NPM_PACKAGE_ARG_8909_STRICT = '1'
665+
666+ t . throws ( ( ) => npa ( 'file://.' ) , {
667+ message : 'Invalid file: URL, must be absolute if // present' ,
668+ raw : 'file://.' ,
669+ } )
670+
671+ t . throws ( ( ) => npa ( 'file://some/relative/path' ) , {
672+ message : 'Invalid file: URL, must be absolute if // present' ,
673+ raw : 'file://some/relative/path' ,
674+ } )
675+
676+ // I cannot for the life of me figure out how to make new URL('file:...')
677+ // actually fail to parse. it seems like it accepts any garbage you can
678+ // throw at it. However, because it theoretically CAN throw, here's a test.
679+ t . throws ( ( ) => {
680+ const npa = t . mock ( '../npa.js' , {
681+ url : {
682+ URL : class {
683+ constructor ( ) {
684+ throw new Error ( 'thansk i haet it' )
685+ }
686+ } ,
687+ } ,
688+ } )
689+ npa ( 'file:thansk i haet it' )
690+ } , {
691+ message : 'Invalid file: URL, must comply with RFC 8909' ,
692+ } )
693+
619694 t . end ( )
620695} )
0 commit comments