You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -96,28 +96,27 @@ Therefore, let's start by exploring the core visitors provided by this package.
96
96
97
97
### Filtering node kinds
98
98
99
-
Before we list each available core visitor, it is important to know that each of these functions optionally accepts a node kind or an array of node kinds **as their last argument**. This allows us to restrict the visitor to a specific set of nodes and will return a `Visitor<T, U>` instance where `U` is the union of the provided node kinds.
99
+
Before we list each available core visitor, it is important to know that each of these functions optionally accepts a node kind or an array of node kinds **as a `keys` attribute in their `options`**. This allows us to restrict the visitor to a specific set of nodes and will return a `Visitor<T, U>` instance where `U` is the union of the provided node kinds.
In the following sections describing the core visitors, this exact pattern can be used to restrict the visitors to specific node kinds. We won't cover this for each visitor but know that you can achieve this via the last argument of each function.
119
+
In the following sections describing the core visitors, this exact pattern can be used to restrict the visitors to specific node kinds. We won't cover this for each visitor but know that you can achieve this via the `keys` option of each function.
The `NodePath` type defines an immutable array of `Nodes` that represents any path of nodes in the Codama IDL. It accepts an optional type parameter that tells us the type of the last node in the path. For instance `NodePath<NumberTypeNode>` represents a path of node ending with a `NumberTypeNode`.
415
+
416
+
Additionally, there are several utility functions to use with `NodePath` instances:
The `NodeStack` class is a utility that allows us to record the stack of nodes that led to a specific node.
458
+
The `NodeStack` class is a utility that allows us to record the path of nodes that led to the node being currently visited. It is essentially a mutable version of `NodePath` that pushes and pops `Nodes` as we go down and up the tree of nodes.
416
459
417
460
For instance, consider the following node:
418
461
@@ -432,49 +475,85 @@ const stack = new NodeStack()
432
475
.push(node.type.items[0]); // -> numberTypeNode.
433
476
```
434
477
435
-
Once you have access to a `NodeStack` instance — provided by various utility visitors — you may use the following methods:
478
+
Once you have access to a `NodeStack` instance, you may use the following methods:
436
479
437
480
```ts
438
481
// Push a node to the stack.
439
482
nodeStack.push(node);
483
+
440
484
// Pop the last node out of the stack.
441
485
const lastNode =nodeStack.pop();
486
+
442
487
// Peek at the last node in the stack.
443
488
const lastNode =nodeStack.peek();
444
-
// Get all the nodes in the stack as an array.
445
-
const path =nodeStack.getPath();
489
+
490
+
// Get all the nodes in the stack as an immutable `NodePath` array.
491
+
const path:NodePath=nodeStack.getPath();
492
+
493
+
// Get a `NodePath` whilst asserting on the last node kind.
Additionally, it is possible to save and restore multiple node paths within a `NodeStack` by using the `pushPath` and `popPath` methods. This is for more advanced uses cases where you need to jump from one part of the tree, to a different part of the tree, and back — without loosing the context of the original path. An application of this is when we need to follow a node from a `LinkNode` (see ["Resolving link nodes"](#resolving-link-nodes) below for more details).
// Pop the current path and restore the previous path.
510
+
const previousPath =stack.popPath();
511
+
```
512
+
452
513
### `recordNodeStackVisitor`
453
514
454
515
The `recordNodeStackVisitor` function gives us a convenient way to record the stack of each node currently being visited. It accepts a base visitor and an empty `NodeStack` instance that will automatically be pushed and popped as the visitor traverses the nodes. This means that we can inject the `NodeStack` instance into another extension of the visitor to access the stack whilst visiting the nodes.
455
516
517
+
Note that the `recordNodeStackVisitor`**should be the last visitor** in the pipe to ensure that the stack is correctly recorded and that the current node visited is part of the stack.
518
+
456
519
For instance, here's how we can log the `NodeStack` of any base visitor as we visit the nodes.
457
520
458
521
```ts
459
522
const stack =newNodeStack();
460
523
const visitor =pipe(
461
524
baseVisitor,
462
-
v=>recordNodeStackVisitor(v, stack),
463
525
v=>
464
526
interceptVisitor(v, (node, next) => {
465
527
console.log(nodePathToString(stack.getPath()));
466
528
returnnext(node);
467
529
}),
530
+
v=>recordNodeStackVisitor(v, stack),
531
+
);
532
+
```
533
+
534
+
Also note that some core visitors such as the `bottomUpTransformerVisitor` or the `getByteSizeVisitor` use a `NodeStack` internally to keep track of the current path. If you use these visitor within another visitor, you may wish to provide your own `NodeStack` instance as an option so that the same `NodeStack` is used across all visitors throughout the traversal.
console.log(`The byte size of ${node.name} is ${byteSize}`);
545
+
}),
546
+
v=>recordNodeStackVisitor(v, stack),
468
547
);
469
548
```
470
549
471
550
## Selecting nodes
472
551
473
552
When visiting a tree of nodes, it is often useful to be explicit about the paths we want to select. For instance, I may want to delete all accounts from a program node named "token".
474
553
475
-
To take end, the `NodeSelector` type represents a node selection that can take two forms:
554
+
To that end, the `NodeSelector` type represents a node selection that can take two forms:
476
555
477
-
- A `NodeSelectorFunction` of type `(node: Node, stack: NodeStack) => boolean`. In this case, the provided function is used to determine if the node should be selected.
556
+
- A `NodeSelectorFunction` of type `(path: NodePath) => boolean`. In this case, the provided function is used to determine if the last node in the provided `NodePath` should be selected.
478
557
- A `NodeSelectorPath` of type `string`. In this case, the provided string uses a simple syntax to select nodes.
By default, this visitor will keep track of its own `NodeStack` but you may provide your own via the `stack` option in order to share the same `NodeStack` across multiple visitors.
643
+
563
644
### `topDownTransformerVisitor`
564
645
565
646
The `topDownTransformerVisitor` works the same way as the `bottomUpTransformerVisitor` but intercepts the nodes on the way down. This means that when we reach a node, we have not yet visited its children.
Here as well, you may use the `stack` option to provide your own `NodeStack` instance.
665
+
583
666
### `deleteNodesVisitor`
584
667
585
668
The `deleteNodesVisitor` accepts an array of `NodeSelectors` and deletes all the nodes that match any of the provided selectors. Therefore, it is equivalent to using a transformer visitor such that the `transform` function returns `null` for the selected nodes.
@@ -589,6 +672,8 @@ The `deleteNodesVisitor` accepts an array of `NodeSelectors` and deletes all the
Here as well, you may use the `stack` option to provide your own `NodeStack` instance.
676
+
592
677
## String representations
593
678
594
679
This package also offers visitors that help render nodes as strings. These visitors can be useful for debugging purposes as well as getting a unique hash string representation of a node.
@@ -648,25 +733,43 @@ const linkables = new LinkableDictionary();
- The stack of the recorded node must be provided when recording a linkable node.
661
-
- The stack of the link node must be provided when getting a linkable node from it.
751
+
- The path of the recorded node must be provided when recording a linkable node.
752
+
- The path of the link node must be provided when getting a linkable node (or its path) from it.
662
753
663
-
This API may be used with the `recordLinkablesOnFirstVisitVisitor` to record the linkable nodes before the first node visit; as well as the `recordNodeStackVisitor` to keep track of the current node stack when accessing the linkable nodes.
754
+
This API may be used with the `recordLinkablesOnFirstVisitVisitor` to record the linkable nodes before the first node visit; as well as the `recordNodeStackVisitor` to keep track of the current node path when accessing the linkable nodes.
755
+
756
+
### `getRecordLinkablesVisitor`
757
+
758
+
This visitor accepts a `LinkableDictionary` instance and records all linkable nodes it encounters when visiting the nodes.
// Now, all linkable nodes are recorded in the `linkables` dictionary.
764
+
```
664
765
665
766
### `recordLinkablesOnFirstVisitVisitor`
666
767
667
-
Much like the `recordNodeStackVisitor`, the `recordLinkablesOnFirstVisitVisitor` allows us to record linkable nodes as we traverse the tree of nodes. It accepts a base visitor and `LinkableDictionary` instance; and records any linkable node it encounters.
768
+
This visitor is a utility that combines `interceptFirstVisitVisitor` and `getRecordLinkablesVisitor`to record all linkable nodes before the first visit of any node.
668
769
669
-
This means that we can inject the `LinkableDictionary` instance into another extension of the base visitor to resolve any link node we encounter.
770
+
It accepts a base visitor and a `LinkableDictionary` instance; and returns a new visitor that records all linkable nodes it encounters before the very first visit of the provided base visitor. This means that we can inject the `LinkableDictionary` instance into other extensions of the base visitor to resolve any link node we encounter.
771
+
772
+
Note that the `recordLinkablesOnFirstVisitVisitor`**should be the last visitor** in the pipe to ensure that all linkable nodes are recorded before being used.
670
773
671
774
Here's an example that records a `LinkableDictionary` and uses it to log the amount of seeds in each linked PDA node.
Note that the `recordLinkablesOnFirstVisitVisitor` should be the last visitor in the pipe to ensure that all linkable nodes are recorded before being used.
689
-
690
791
## Other useful visitors
691
792
692
793
This package provides a few other visitors that may help build more complex visitors.
// ^ 36 (4 bytes for the u32 number and 32 bytes for the public key)
702
803
```
703
804
805
+
By default, this visitor will keep track of its own `NodeStack` but you may provide your own via the `stack` option in order to share the same `NodeStack` across multiple visitors.
806
+
704
807
### `getResolvedInstructionInputsVisitor`
705
808
706
809
The `getResolvedInstructionInputsVisitor` visits `InstructionNodes` only and returns an array of instruction accounts and arguments in the order they should be rendered for their default values to be resolved.
0 commit comments