@@ -2,65 +2,24 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
22import * as fs from 'fs/promises' ;
33import * as path from 'path' ;
44import * as os from 'os' ;
5+ import { buildDirectoryTree , setAllowedDirectories } from '../lib.js' ;
56
6- // We need to test the buildTree function, but it's defined inside the request handler
7- // So we'll extract the core logic into a testable function
8- import { minimatch } from 'minimatch' ;
9-
10- interface TreeEntry {
11- name : string ;
12- type : 'file' | 'directory' ;
13- children ?: TreeEntry [ ] ;
14- }
15-
16- async function buildTreeForTesting ( currentPath : string , rootPath : string , excludePatterns : string [ ] = [ ] ) : Promise < TreeEntry [ ] > {
17- const entries = await fs . readdir ( currentPath , { withFileTypes : true } ) ;
18- const result : TreeEntry [ ] = [ ] ;
19-
20- for ( const entry of entries ) {
21- const relativePath = path . relative ( rootPath , path . join ( currentPath , entry . name ) ) ;
22- const shouldExclude = excludePatterns . some ( pattern => {
23- if ( pattern . includes ( '*' ) ) {
24- return minimatch ( relativePath , pattern , { dot : true } ) ;
25- }
26- // For files: match exact name or as part of path
27- // For directories: match as directory path
28- return minimatch ( relativePath , pattern , { dot : true } ) ||
29- minimatch ( relativePath , `**/${ pattern } ` , { dot : true } ) ||
30- minimatch ( relativePath , `**/${ pattern } /**` , { dot : true } ) ;
31- } ) ;
32- if ( shouldExclude )
33- continue ;
34-
35- const entryData : TreeEntry = {
36- name : entry . name ,
37- type : entry . isDirectory ( ) ? 'directory' : 'file'
38- } ;
39-
40- if ( entry . isDirectory ( ) ) {
41- const subPath = path . join ( currentPath , entry . name ) ;
42- entryData . children = await buildTreeForTesting ( subPath , rootPath , excludePatterns ) ;
43- }
44-
45- result . push ( entryData ) ;
46- }
47-
48- return result ;
49- }
50-
51- describe ( 'buildTree exclude patterns' , ( ) => {
7+ describe ( 'buildDirectoryTree exclude patterns' , ( ) => {
528 let testDir : string ;
539
5410 beforeEach ( async ( ) => {
55- testDir = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , 'filesystem-test-' ) ) ;
56-
57- // Create test directory structure
11+ // On macOS, os.tmpdir() returns /var/folders/... which symlinks to
12+ // /private/var/folders/..., and validatePath compares against the
13+ // resolved real path. Resolve once up front so allowedDirectories
14+ // matches what the recursion sees.
15+ testDir = await fs . realpath ( await fs . mkdtemp ( path . join ( os . tmpdir ( ) , 'filesystem-test-' ) ) ) ;
16+ setAllowedDirectories ( [ testDir ] ) ;
17+
5818 await fs . mkdir ( path . join ( testDir , 'src' ) ) ;
5919 await fs . mkdir ( path . join ( testDir , 'node_modules' ) ) ;
6020 await fs . mkdir ( path . join ( testDir , '.git' ) ) ;
6121 await fs . mkdir ( path . join ( testDir , 'nested' , 'node_modules' ) , { recursive : true } ) ;
62-
63- // Create test files
22+
6423 await fs . writeFile ( path . join ( testDir , '.env' ) , 'SECRET=value' ) ;
6524 await fs . writeFile ( path . join ( testDir , '.env.local' ) , 'LOCAL_SECRET=value' ) ;
6625 await fs . writeFile ( path . join ( testDir , 'src' , 'index.js' ) , 'console.log("hello");' ) ;
@@ -71,62 +30,60 @@ describe('buildTree exclude patterns', () => {
7130
7231 afterEach ( async ( ) => {
7332 await fs . rm ( testDir , { recursive : true , force : true } ) ;
33+ setAllowedDirectories ( [ ] ) ;
7434 } ) ;
7535
7636 it ( 'should exclude files matching simple patterns' , async ( ) => {
77- // Test the current implementation - this will fail until the bug is fixed
78- const tree = await buildTreeForTesting ( testDir , testDir , [ '.env' ] ) ;
37+ const tree = await buildDirectoryTree ( testDir , [ '.env' ] ) ;
7938 const fileNames = tree . map ( entry => entry . name ) ;
80-
39+
8140 expect ( fileNames ) . not . toContain ( '.env' ) ;
82- expect ( fileNames ) . toContain ( '.env.local' ) ; // Should not exclude this
41+ expect ( fileNames ) . toContain ( '.env.local' ) ;
8342 expect ( fileNames ) . toContain ( 'src' ) ;
8443 expect ( fileNames ) . toContain ( 'package.json' ) ;
8544 } ) ;
8645
8746 it ( 'should exclude directories matching simple patterns' , async ( ) => {
88- const tree = await buildTreeForTesting ( testDir , testDir , [ 'node_modules' ] ) ;
47+ const tree = await buildDirectoryTree ( testDir , [ 'node_modules' ] ) ;
8948 const dirNames = tree . map ( entry => entry . name ) ;
90-
49+
9150 expect ( dirNames ) . not . toContain ( 'node_modules' ) ;
9251 expect ( dirNames ) . toContain ( 'src' ) ;
9352 expect ( dirNames ) . toContain ( '.git' ) ;
9453 } ) ;
9554
9655 it ( 'should exclude nested directories with same pattern' , async ( ) => {
97- const tree = await buildTreeForTesting ( testDir , testDir , [ 'node_modules' ] ) ;
98-
99- // Find the nested directory
56+ const tree = await buildDirectoryTree ( testDir , [ 'node_modules' ] ) ;
57+
10058 const nestedDir = tree . find ( entry => entry . name === 'nested' ) ;
10159 expect ( nestedDir ) . toBeDefined ( ) ;
10260 expect ( nestedDir ! . children ) . toBeDefined ( ) ;
103-
104- // The nested/node_modules should also be excluded
61+
10562 const nestedChildren = nestedDir ! . children ! . map ( child => child . name ) ;
10663 expect ( nestedChildren ) . not . toContain ( 'node_modules' ) ;
10764 } ) ;
10865
10966 it ( 'should handle glob patterns correctly' , async ( ) => {
110- const tree = await buildTreeForTesting ( testDir , testDir , [ '*.env' ] ) ;
67+ const tree = await buildDirectoryTree ( testDir , [ '*.env' ] ) ;
11168 const fileNames = tree . map ( entry => entry . name ) ;
112-
69+
11370 expect ( fileNames ) . not . toContain ( '.env' ) ;
114- expect ( fileNames ) . toContain ( '.env.local' ) ; // *.env should not match .env.local
71+ expect ( fileNames ) . toContain ( '.env.local' ) ;
11572 expect ( fileNames ) . toContain ( 'src' ) ;
11673 } ) ;
11774
11875 it ( 'should handle dot files correctly' , async ( ) => {
119- const tree = await buildTreeForTesting ( testDir , testDir , [ '.git' ] ) ;
76+ const tree = await buildDirectoryTree ( testDir , [ '.git' ] ) ;
12077 const dirNames = tree . map ( entry => entry . name ) ;
121-
78+
12279 expect ( dirNames ) . not . toContain ( '.git' ) ;
123- expect ( dirNames ) . toContain ( '.env' ) ; // Should not exclude this
80+ expect ( dirNames ) . toContain ( '.env' ) ;
12481 } ) ;
12582
12683 it ( 'should work with multiple exclude patterns' , async ( ) => {
127- const tree = await buildTreeForTesting ( testDir , testDir , [ 'node_modules' , '.env' , '.git' ] ) ;
84+ const tree = await buildDirectoryTree ( testDir , [ 'node_modules' , '.env' , '.git' ] ) ;
12885 const entryNames = tree . map ( entry => entry . name ) ;
129-
86+
13087 expect ( entryNames ) . not . toContain ( 'node_modules' ) ;
13188 expect ( entryNames ) . not . toContain ( '.env' ) ;
13289 expect ( entryNames ) . not . toContain ( '.git' ) ;
@@ -135,13 +92,12 @@ describe('buildTree exclude patterns', () => {
13592 } ) ;
13693
13794 it ( 'should handle empty exclude patterns' , async ( ) => {
138- const tree = await buildTreeForTesting ( testDir , testDir , [ ] ) ;
95+ const tree = await buildDirectoryTree ( testDir , [ ] ) ;
13996 const entryNames = tree . map ( entry => entry . name ) ;
140-
141- // All entries should be included
97+
14298 expect ( entryNames ) . toContain ( 'node_modules' ) ;
14399 expect ( entryNames ) . toContain ( '.env' ) ;
144100 expect ( entryNames ) . toContain ( '.git' ) ;
145101 expect ( entryNames ) . toContain ( 'src' ) ;
146102 } ) ;
147- } ) ;
103+ } ) ;
0 commit comments