@@ -33,6 +33,33 @@ const fs = require('fs')
3333const glob = require ( 'glob' )
3434const globify = pattern => pattern . split ( '\\' ) . join ( '/' )
3535
36+ const readOutOfTreeIgnoreFiles = ( root , rel , result = '' ) => {
37+ for ( const file of [ '.gitignore' , '.npmignore' ] ) {
38+ try {
39+ const ignoreContent = fs . readFileSync ( path . join ( root , file ) , { encoding : 'utf8' } )
40+ result += ignoreContent + '\n'
41+ } catch ( err ) {
42+ // we ignore ENOENT errors completely because we don't care if the file doesn't exist
43+ // but we throw everything else because failing to read a file that does exist is
44+ // something that the user likely wants to know about. we don't need to test this.
45+ /* istanbul ignore next */
46+ if ( err . code !== 'ENOENT' ) {
47+ throw err
48+ }
49+ }
50+ }
51+
52+ if ( ! rel ) {
53+ return result
54+ }
55+
56+ const firstRel = rel . split ( path . sep ) [ 0 ]
57+ const newRoot = path . join ( root , firstRel )
58+ const newRel = path . relative ( newRoot , path . join ( root , rel ) )
59+
60+ return readOutOfTreeIgnoreFiles ( newRoot , newRel , result )
61+ }
62+
3663const pathHasPkg = ( input ) => {
3764 if ( ! input . startsWith ( 'node_modules/' ) ) {
3865 return false
@@ -119,9 +146,31 @@ class Walker extends IgnoreWalker {
119146 this . bundledScopes = Array . from ( new Set (
120147 this . bundled . filter ( f => / ^ @ / . test ( f ) )
121148 . map ( f => f . split ( '/' ) [ 0 ] ) ) )
122- const rules = defaultRules . join ( '\n' ) + '\n'
123149 this . packageJsonCache = this . parent ? this . parent . packageJsonCache
124150 : ( opt . packageJsonCache || new Map ( ) )
151+ let rules = defaultRules . join ( '\n' ) + '\n'
152+
153+ if ( opt . prefix && opt . workspaces ) {
154+ const gPath = globify ( opt . path )
155+ const gPrefix = globify ( opt . prefix )
156+ const gWorkspaces = opt . workspaces . map ( ( ws ) => globify ( ws ) )
157+ // if opt.path and opt.prefix are not the same directory, and opt.workspaces has opt.path
158+ // in it, then we know that opt.path is a workspace directory. in order to not drop ignore
159+ // rules from directories between the workspace root (opt.prefix) and the workspace itself
160+ // (opt.path), we need to find and read those now
161+ /* istanbul ignore else */
162+ if ( gPath !== gPrefix && gWorkspaces . includes ( gPath ) ) {
163+ // relpath is the relative path between the prefix and the parent of opt.path
164+ // we use the parent because ignore-walk will read the files in opt.path already
165+ const relpath = path . relative ( opt . prefix , path . dirname ( opt . path ) )
166+ rules += readOutOfTreeIgnoreFiles ( opt . prefix , relpath )
167+ } else if ( gPath === gPrefix ) {
168+ // on the other hand, if the path and the prefix are the same, then we ignore workspaces
169+ // so that we don't pack workspaces inside of a root project
170+ rules += opt . workspaces . map ( ( ws ) => globify ( path . relative ( opt . path , ws ) ) ) . join ( '\n' )
171+ }
172+ }
173+
125174 super . onReadIgnoreFile ( rootBuiltinRules , rules , _ => _ )
126175 } else {
127176 this . bundled = [ ]
0 commit comments