@@ -30,6 +30,12 @@ export interface IndexOptions {
3030 dryRun : boolean ;
3131 /** Enable verbose output with detailed progress information */
3232 verbose : boolean ;
33+ /** Maximum depth to traverse subdirectories */
34+ maxDepth ?: number ;
35+ /** Prevent traversing up from the specified directory */
36+ noTraverseUp : boolean ;
37+ /** Explicit boundary path to limit scanning scope */
38+ boundary ?: string ;
3339}
3440
3541/**
@@ -93,6 +99,9 @@ interface IndexCliOptions {
9399 template ?: string ;
94100 dryRun ?: boolean ;
95101 verbose ?: boolean ;
102+ maxDepth ?: number ;
103+ noTraverseUp ?: boolean ;
104+ boundary ?: string ;
96105}
97106
98107export async function indexCommand (
@@ -107,7 +116,10 @@ export async function indexCommand(
107116 embedStyle : cliOptions . embedStyle || 'obsidian' ,
108117 dryRun : cliOptions . dryRun || false ,
109118 verbose : cliOptions . verbose || false ,
119+ noTraverseUp : cliOptions . noTraverseUp || false ,
110120 ...( cliOptions . template && { template : cliOptions . template } ) ,
121+ ...( cliOptions . maxDepth !== undefined && { maxDepth : cliOptions . maxDepth } ) ,
122+ ...( cliOptions . boundary && { boundary : cliOptions . boundary } ) ,
111123 } ;
112124
113125 return generateIndexFiles ( options , directory || '.' ) ;
@@ -170,12 +182,58 @@ async function discoverMarkdownFiles(
170182 targetDir : string ,
171183 options : IndexOptions
172184) : Promise < IndexableFile [ ] > {
173- const pattern = join ( targetDir , '**/*.md' ) ;
174- const filePaths = await glob ( pattern , { ignore : [ '**/node_modules/**' ] } ) ;
185+ // Determine the effective boundary for file scanning
186+ const effectiveBoundary = options . boundary ? resolve ( options . boundary ) : targetDir ;
187+
188+ // Build glob pattern based on maxDepth option
189+ let globPattern : string ;
190+ if ( options . maxDepth !== undefined ) {
191+ // Create depth-limited pattern
192+ const depthPattern = Array . from ( { length : options . maxDepth } , ( ) => '*' ) . join ( '/' ) ;
193+ globPattern = join ( targetDir , depthPattern , '*.md' ) ;
194+ } else {
195+ globPattern = join ( targetDir , '**/*.md' ) ;
196+ }
197+
198+ const globOptions : Parameters < typeof glob > [ 1 ] = {
199+ ignore : [ '**/node_modules/**' ] ,
200+ } ;
201+
202+ // Only set cwd if noTraverseUp is enabled
203+ if ( options . noTraverseUp ) {
204+ globOptions . cwd = targetDir ;
205+ }
206+
207+ const filePaths = await glob ( globPattern , globOptions ) ;
208+
209+ // Filter files to respect boundary constraints and convert Path objects to strings
210+ const boundaryFilePaths = filePaths
211+ . map ( filePath => typeof filePath === 'string' ? filePath : filePath . toString ( ) )
212+ . filter ( filePath => {
213+ const resolvedPath = resolve ( filePath ) ;
214+
215+ // Ensure file is within the boundary directory
216+ if ( options . boundary ) {
217+ const relativeToBoundary = relative ( effectiveBoundary , resolvedPath ) ;
218+ if ( relativeToBoundary . startsWith ( '..' ) ) {
219+ return false ; // File is outside boundary
220+ }
221+ }
222+
223+ // Ensure file is within or below target directory when noTraverseUp is enabled
224+ if ( options . noTraverseUp ) {
225+ const relativeToTarget = relative ( targetDir , resolvedPath ) ;
226+ if ( relativeToTarget . startsWith ( '..' ) ) {
227+ return false ; // File is above target directory
228+ }
229+ }
230+
231+ return true ;
232+ } ) ;
175233
176234 const files : IndexableFile [ ] = [ ] ;
177235
178- for ( const filePath of filePaths ) {
236+ for ( const filePath of boundaryFilePaths ) {
179237 // Skip existing index files if they match our naming pattern
180238 const fileName = filePath . split ( '/' ) . pop ( ) || '' ;
181239 if ( fileName === options . name ) {
0 commit comments