@@ -2,7 +2,7 @@ import { Expression, Statement, Node, NodePath } from './types'
2
2
import { Backend } from './backend/Backend'
3
3
import find , { Match , convertWithCaptures , createMatch } from './find'
4
4
import replace from './replace'
5
- import compileMatcher , { MatchResult } from './compileMatcher'
5
+ import compileMatcher , { CompiledMatcher , MatchResult } from './compileMatcher'
6
6
import CodeFrameError from './util/CodeFrameError'
7
7
import ensureArray from './util/ensureArray'
8
8
import * as AstTypes from 'ast-types'
@@ -13,6 +13,7 @@ import {
13
13
getRestPlaceholder ,
14
14
} from './compileMatcher/Placeholder'
15
15
import { SimpleReplacementInterface } from './util/SimpleReplacementCollector'
16
+ import forEachNode from './util/forEachNode'
16
17
17
18
export type TransformOptions = {
18
19
/** The absolute path to the current file. */
@@ -60,6 +61,8 @@ export type GetReplacement = (
60
61
parse : ParsePattern
61
62
) => string | Node | Node [ ]
62
63
64
+ export type FindPredicate = ( wrapper : Astx ) => boolean
65
+
63
66
function isNode ( x : unknown ) : x is Node {
64
67
return x instanceof Object && typeof ( x as any ) . type === 'string'
65
68
}
@@ -374,12 +377,75 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
374
377
}
375
378
}
376
379
380
+ private _execPatternOrPredicate < Options > (
381
+ name : string ,
382
+ exec : ( match : CompiledMatcher [ 'match' ] , options ?: Options ) => Astx ,
383
+ arg0 :
384
+ | string
385
+ | Node
386
+ | Node [ ]
387
+ | NodePath < any >
388
+ | NodePath < any > [ ]
389
+ | string [ ]
390
+ | TemplateStringsArray
391
+ | FindPredicate ,
392
+ ...rest : any [ ]
393
+ ) : Astx | ( ( options ?: Options ) => Astx ) {
394
+ const { backend } = this
395
+ if ( arg0 instanceof Function ) {
396
+ const predicate = arg0
397
+ const options = rest [ 0 ]
398
+ const match = ( path : NodePath ) : MatchResult => {
399
+ const wrapper = new Astx ( this . context , [ path ] , {
400
+ withCaptures : this . _matches ,
401
+ } )
402
+ return predicate ( wrapper ) ? wrapper . initialMatch || { } : null
403
+ }
404
+ try {
405
+ return exec ( match , options )
406
+ } catch ( error ) {
407
+ if ( error instanceof Error ) {
408
+ CodeFrameError . rethrow ( error , {
409
+ filename : `${ name } pattern` ,
410
+ } )
411
+ }
412
+ throw error
413
+ }
414
+ } else {
415
+ return this . _execPattern (
416
+ name ,
417
+ (
418
+ pattern : NodePath < Node , any > | readonly NodePath < Node , any > [ ] ,
419
+ options ?: Options
420
+ ) => {
421
+ pattern = ensureArray ( pattern )
422
+ if ( pattern . length !== 1 ) {
423
+ throw new Error ( `must be a single node` )
424
+ }
425
+ const matcher = compileMatcher ( pattern [ 0 ] , {
426
+ ...options ,
427
+ backend,
428
+ } )
429
+ return exec ( matcher . match , options )
430
+ } ,
431
+ arg0 ,
432
+ ...rest
433
+ )
434
+ }
435
+ }
436
+
377
437
closest (
378
438
strings : TemplateStringsArray ,
379
439
...quasis : any [ ]
380
440
) : ( options ?: FindOptions ) => Astx
381
441
closest (
382
- pattern : string | Node | Node [ ] | NodePath < any > | NodePath < any > [ ] ,
442
+ pattern :
443
+ | string
444
+ | Node
445
+ | Node [ ]
446
+ | NodePath < any >
447
+ | NodePath < any > [ ]
448
+ | FindPredicate ,
383
449
options ?: FindOptions
384
450
) : Astx
385
451
closest (
@@ -389,39 +455,27 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
389
455
| Node [ ]
390
456
| NodePath < any >
391
457
| NodePath < any > [ ]
392
- | TemplateStringsArray ,
458
+ | TemplateStringsArray
459
+ | FindPredicate ,
393
460
...rest : any [ ]
394
461
) : Astx | ( ( options ?: FindOptions ) => Astx ) {
395
- const { context, backend } = this
396
- return this . _execPattern (
462
+ const { context } = this
463
+ return this . _execPatternOrPredicate (
397
464
'closest' ,
398
- (
399
- pattern : NodePath < Node , any > | readonly NodePath < Node , any > [ ] ,
400
- options ?: FindOptions
401
- ) : Astx => {
402
- pattern = ensureArray ( pattern )
403
- if ( pattern . length !== 1 ) {
404
- throw new Error ( `must be a single node` )
405
- }
406
- const matcher = compileMatcher ( pattern [ 0 ] , {
407
- ...options ,
408
- backend,
409
- } )
410
-
465
+ ( matcher : CompiledMatcher [ 'match' ] ) : Astx => {
411
466
const matchedParents : Set < NodePath > = new Set ( )
412
467
const matches : Match [ ] = [ ]
413
468
this . paths . forEach ( ( path ) => {
414
469
for ( let p = path . parentPath ; p ; p = p . parentPath ) {
415
470
if ( matchedParents . has ( p ) ) return
416
- const match = matcher . match ( p , this . initialMatch )
471
+ const match = matcher ( p , this . initialMatch )
417
472
if ( match ) {
418
473
matchedParents . add ( p )
419
474
matches . push ( createMatch ( p , match ) )
420
475
return
421
476
}
422
477
}
423
478
} )
424
-
425
479
return new Astx ( context , matches )
426
480
} ,
427
481
arg0 ,
@@ -434,7 +488,13 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
434
488
...quasis : any [ ]
435
489
) : ( options ?: FindOptions ) => Astx
436
490
destruct (
437
- pattern : string | Node | Node [ ] | NodePath < any > | NodePath < any > [ ] ,
491
+ pattern :
492
+ | string
493
+ | Node
494
+ | Node [ ]
495
+ | NodePath < any >
496
+ | NodePath < any > [ ]
497
+ | FindPredicate ,
438
498
options ?: FindOptions
439
499
) : Astx
440
500
destruct (
@@ -444,31 +504,19 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
444
504
| Node [ ]
445
505
| NodePath < any >
446
506
| NodePath < any > [ ]
447
- | TemplateStringsArray ,
507
+ | TemplateStringsArray
508
+ | FindPredicate ,
448
509
...rest : any [ ]
449
510
) : Astx | ( ( options ?: FindOptions ) => Astx ) {
450
- const { context, backend } = this
451
- return this . _execPattern (
511
+ const { context } = this
512
+ return this . _execPatternOrPredicate (
452
513
'destruct' ,
453
- (
454
- pattern : NodePath < Node , any > | readonly NodePath < Node , any > [ ] ,
455
- options ?: FindOptions
456
- ) : Astx => {
457
- pattern = ensureArray ( pattern )
458
- if ( pattern . length !== 1 ) {
459
- throw new Error ( `must be a single node` )
460
- }
461
- const matcher = compileMatcher ( pattern [ 0 ] , {
462
- ...options ,
463
- backend,
464
- } )
465
-
514
+ ( matcher : CompiledMatcher [ 'match' ] ) : Astx => {
466
515
const matches : Match [ ] = [ ]
467
516
this . paths . forEach ( ( path ) => {
468
- const match = matcher . match ( path , this . initialMatch )
517
+ const match = matcher ( path , this . initialMatch )
469
518
if ( match ) matches . push ( createMatch ( path , match ) )
470
519
} )
471
-
472
520
return new Astx ( context , matches )
473
521
} ,
474
522
arg0 ,
@@ -481,7 +529,13 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
481
529
...quasis : any [ ]
482
530
) : ( options ?: FindOptions ) => Astx
483
531
find (
484
- pattern : string | Node | Node [ ] | NodePath < any > | NodePath < any > [ ] ,
532
+ pattern :
533
+ | string
534
+ | Node
535
+ | Node [ ]
536
+ | NodePath < any >
537
+ | NodePath < any > [ ]
538
+ | FindPredicate ,
485
539
options ?: FindOptions
486
540
) : Astx
487
541
find (
@@ -492,10 +546,24 @@ export default class Astx extends ExtendableProxy implements Iterable<Astx> {
492
546
| NodePath < any >
493
547
| NodePath < any > [ ]
494
548
| string [ ]
495
- | TemplateStringsArray ,
549
+ | TemplateStringsArray
550
+ | FindPredicate ,
496
551
...rest : any [ ]
497
552
) : Astx | ( ( options ?: FindOptions ) => Astx ) {
498
553
const { context, backend } = this
554
+ if ( arg0 instanceof Function ) {
555
+ const predicate = arg0
556
+ const matches : Match [ ] = [ ]
557
+ forEachNode ( backend . t , this . paths , [ 'Node' ] , ( path : NodePath ) => {
558
+ const wrapper = new Astx ( this . context , [ path ] , {
559
+ withCaptures : this . _matches ,
560
+ } )
561
+ if ( predicate ( wrapper ) ) {
562
+ matches . push ( createMatch ( path , wrapper . initialMatch || { } ) )
563
+ }
564
+ } )
565
+ return new Astx ( context , matches )
566
+ }
499
567
return this . _execPattern (
500
568
'find' ,
501
569
(
0 commit comments