diff --git a/src/types/__tests__/visitor.spec-d.ts b/src/types/__tests__/visitor.spec-d.ts new file mode 100644 index 0000000..1ee1b40 --- /dev/null +++ b/src/types/__tests__/visitor.spec-d.ts @@ -0,0 +1,62 @@ +/** + * @file Type Tests - Visitor + * @module unist-util-visit/types/tests/unit-d/Visitor + */ + +import type * as docast from '@flex-development/docast' +import type { Optional } from '@flex-development/tutils' +import type { + Index, + MatchInclusiveDescendant, + Type +} from '@flex-development/unist-util-types' +import type VisitedAncestor from '../visited-ancestor' +import type VisitedParent from '../visited-parent' +import type TestSubject from '../visitor' +import type VisitorResult from '../visitor-result' + +describe('unit-d:types/Visitor', () => { + type Tree = docast.Root + type Check = Type + type Subject = TestSubject + + it('should match [this: void]', () => { + expectTypeOf().thisParameter.toBeVoid() + }) + + describe('parameters', () => { + it('should match [0: MatchInclusiveDescendant]', () => { + // Arrange + type Expect = MatchInclusiveDescendant + + // Expect + expectTypeOf().parameter(0).toEqualTypeOf() + }) + + it('should match [1: Optional]', () => { + expectTypeOf().parameter(1).toEqualTypeOf>() + }) + + it('should match [2: Optional>]', () => { + // Arrange + type Expect = Optional> + + // Expect + expectTypeOf().parameter(2).toEqualTypeOf() + }) + + it('should match [3: VisitedAncestor[]]', () => { + // Arrange + type Expect = VisitedAncestor[] + + // Expect + expectTypeOf().parameter(3).toEqualTypeOf() + }) + }) + + describe('returns', () => { + it('should return VisitorResult', () => { + expectTypeOf().returns.toEqualTypeOf() + }) + }) +}) diff --git a/src/types/__tests__/visitors.spec-d.ts b/src/types/__tests__/visitors.spec-d.ts new file mode 100644 index 0000000..80f88d8 --- /dev/null +++ b/src/types/__tests__/visitors.spec-d.ts @@ -0,0 +1,29 @@ +/** + * @file Type Tests - Visitors + * @module unist-util-visit/types/tests/unit-d/Visitors + */ + +import type * as docast from '@flex-development/docast' +import type { Nilable } from '@flex-development/tutils' +import type { Type } from '@flex-development/unist-util-types' +import type Visitor from '../visitor' +import type TestSubject from '../visitors' + +describe('unit-d:types/Visitors', () => { + type Tree = docast.Root + type Check = Type + type VisitorFn = Visitor + type Subject = TestSubject + + it('should match [enter?: Nilable>]', () => { + expectTypeOf() + .toHaveProperty('enter') + .toEqualTypeOf>() + }) + + it('should match [leave?: Nilable>]', () => { + expectTypeOf() + .toHaveProperty('leave') + .toEqualTypeOf>() + }) +}) diff --git a/src/types/index.ts b/src/types/index.ts index 2b47058..a64ea05 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -11,4 +11,6 @@ export type { default as Exit } from './exit' export type { default as Skip } from './skip' export type { default as VisitedAncestor } from './visited-ancestor' export type { default as VisitedParent } from './visited-parent' +export type { default as Visitor } from './visitor' export type { default as VisitorResult } from './visitor-result' +export type { default as Visitors } from './visitors' diff --git a/src/types/visitor.ts b/src/types/visitor.ts new file mode 100644 index 0000000..f2c38ca --- /dev/null +++ b/src/types/visitor.ts @@ -0,0 +1,75 @@ +/** + * @file Type Definitions - Visitor + * @module unist-util-visit/types/Visitor + */ + +import type { Optional } from '@flex-development/tutils' +import type { + Index, + MatchInclusiveDescendant, + Test +} from '@flex-development/unist-util-types' +import type { Node } from 'unist' +import type Action from './action' +import type VisitedAncestor from './visited-ancestor' +import type VisitedParent from './visited-parent' +import type VisitorResult from './visitor-result' + +/** + * Handle visiting `node`. + * + * Visitors are free to transform `node`. They can also transform [`parent`][1], + * or the grandparent of `node` (the last of [`ancestors`][2]). + * + * > 👉 **Note**: Replacing `node` itself, if `SKIP` is not returned, still + * > causes its [*descendants*][3] to be walked (which is a bug). + * + * When adding or removing previous [*siblings*][4] of `node`, the `Visitor` + * should return a new `Index` to specify the sibling to traverse after `node` + * is traversed. Adding or removing next siblings of `node` is handled as + * expected without needing to return a new `Index`. + * + * Removing the [*children*][5] of an [*ancestor*][2] still results in those + * child nodes being traversed. + * + * The `Visitor` should return the next action, or `Index`, as explained above. + * An `Index` is treated as a tuple of `[CONTINUE, Index]`. An `Action` is + * treated as a tuple of `[Action]`. Returning a tuple only makes sense if the + * `Action` is `SKIP`. When the `Action` is `EXIT`, that action can be returned. + * When the `Action` is `CONTINUE`, `Index` can be returned. + * + * [1]: https://github.com/syntax-tree/unist#parent-1 + * [2]: https://github.com/syntax-tree/unist#ancestor + * [3]: https://github.com/syntax-tree/unist#descendant + * [4]: https://github.com/syntax-tree/unist#sibling + * [5]: https://github.com/syntax-tree/unist#child + * + * @see {@linkcode Action} + * @see {@linkcode Index} + * @see {@linkcode MatchInclusiveDescendant} + * @see {@linkcode Node} + * @see {@linkcode Test} + * @see {@linkcode VisitedAncestor} + * @see {@linkcode VisitedParent} + * @see {@linkcode VisitorResult} + * + * @template {Node} [Tree=Node] - Tree being visited + * @template {Test} [Check=Test] - Node test + * + * @this {void} + * + * @param {MatchInclusiveDescendant} node - Found node + * @param {Optional} index - Index of `node` in `parent.children` + * @param {Optional>} parent - Parent of `node` + * @param {VisitedAncestor[]} ancestors - Ancestors of `node` + * @return {VisitorResult} What to do next + */ +type Visitor = ( + this: void, + node: MatchInclusiveDescendant, + index: Optional, + parent: Optional>, + ancestors: VisitedAncestor[] +) => VisitorResult + +export type { Visitor as default } diff --git a/src/types/visitors.ts b/src/types/visitors.ts new file mode 100644 index 0000000..2d61395 --- /dev/null +++ b/src/types/visitors.ts @@ -0,0 +1,43 @@ +/** + * @file Type Definitions - Visitors + * @module unist-util-visit/types/Visitors + */ + +import type { Nilable } from '@flex-development/tutils' +import type { Test } from '@flex-development/unist-util-types' +import type { Node } from 'unist' +import type Visitor from './visitor' + +/** + * Handle nodes when entering ([*preorder*][1]) and leaving ([*postorder*][2]). + * + * [1]: https://github.com/syntax-tree/unist#preorder + * [2]: https://github.com/syntax-tree/unist#postorder + * + * @see {@linkcode Node} + * @see {@linkcode Test} + * + * @template {Node} [Tree=Node] - Tree being visited + * @template {Test} [Check=Test] - Node test + */ +type Visitors = { + /** + * Handle nodes when entering ([*preorder*][1]). + * + * [1]: https://github.com/syntax-tree/unist#preorder + * + * @see {@linkcode Visitor} + */ + enter?: Nilable> + + /** + * Handle nodes when leaving ([*postorder*][1]). + * + * [1]: https://github.com/syntax-tree/unist#postorder + * + * @see {@linkcode Visitor} + */ + leave?: Nilable> +} + +export type { Visitors as default }