Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: syntax-tree/unist-util-visit
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.1.2
Choose a base ref
...
head repository: syntax-tree/unist-util-visit
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5.0.0
Choose a head ref
  • 13 commits
  • 9 files changed
  • 1 contributor

Commits on Jul 6, 2023

  1. Update dev-dependencies

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    dcc26d2 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    7e897eb View commit details
  3. Refactor .npmrc

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    c191c56 View commit details
  4. Refactor code-style

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    57992a3 View commit details
  5. Refactor docs

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    07a2fbe View commit details
  6. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    12c9ee9 View commit details
  7. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3cb2732 View commit details
  8. Change to remove complex-types.d.ts

    All types are now exposed from regular files (`index.js`).
    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    89fc050 View commit details
  9. Remove xo rules

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    77d6cb1 View commit details
  10. Change to use export map

    wooorm committed Jul 6, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b5f36de View commit details
  11. Change to require Node.js 16

    wooorm committed Jul 6, 2023

    Unverified

    This user has not yet uploaded their public signing key.
    Copy the full SHA
    befc0b3 View commit details

Commits on Jul 7, 2023

  1. Update @types/unist

    wooorm committed Jul 7, 2023
    Copy the full SHA
    4dcff31 View commit details
  2. 5.0.0

    wooorm committed Jul 7, 2023
    Copy the full SHA
    bc59f3b View commit details
Showing with 652 additions and 533 deletions.
  1. +2 −2 .gitignore
  2. +1 −1 .npmrc
  3. +0 −2 complex-types.d.ts
  4. +178 −162 index.test-d.ts
  5. +223 −92 lib/index.js
  6. +34 −24 package.json
  7. +34 −33 readme.md
  8. +174 −209 test.js
  9. +6 −8 tsconfig.json
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.DS_Store
lib/index.d.ts
test.d.ts
*.d.ts
*.log
coverage/
node_modules/
yarn.lock
!/index.d.ts
2 changes: 1 addition & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
package-lock=false
ignore-scripts=true
package-lock=false
2 changes: 0 additions & 2 deletions complex-types.d.ts

This file was deleted.

340 changes: 178 additions & 162 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,201 +1,217 @@
/* eslint-disable @typescript-eslint/no-empty-function */

import {expectError, expectType} from 'tsd'
import type {Node, Parent, Literal} from 'unist'
import {is} from 'unist-util-is'
import {visit, SKIP, EXIT, CONTINUE} from './index.js'

/* Setup */
const sampleTree: Root = {
import {expectAssignable, expectNotType, expectType} from 'tsd'
import type {
Blockquote,
Definition,
Delete,
Emphasis,
FootnoteDefinition,
Heading,
Link,
LinkReference,
ListItem,
Nodes,
Parents,
PhrasingContent,
Root,
RootContent,
Strong,
TableCell,
TableRow
} from 'mdast'
import type {Node, Parent} from 'unist'
import {CONTINUE, EXIT, SKIP, visit} from './index.js'

// Setup.
const implicitTree = {
type: 'root',
children: [{type: 'heading', depth: 1, children: []}]
}

const complexTree: Root = {
const sampleTree: Root = {
type: 'root',
children: [
{
type: 'blockquote',
children: [{type: 'paragraph', children: [{type: 'text', value: 'a'}]}]
},
{
type: 'paragraph',
children: [
{
type: 'emphasis',
children: [{type: 'emphasis', children: [{type: 'text', value: 'b'}]}]
},
{type: 'text', value: 'c'}
]
}
]
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Element extends Parent {
type: 'element'
tagName: string
properties: Record<string, unknown>
content: Node
children: Array<Node>
children: [{type: 'heading', depth: 1, children: []}]
}

type Content = Flow | Phrasing
// ## Missing parameters
// @ts-expect-error: check that `node` is passed.
visit()
// @ts-expect-error: check that `visitor` is passed.
visit(sampleTree)

// ## No test
visit(sampleTree, function (node, index, parent) {
expectType<Nodes>(node)
expectType<number | undefined>(index)
expectType<Parents | undefined>(parent)
})

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Root extends Parent {
type: 'root'
children: Array<Flow>
}
visit(implicitTree, function (node, index, parent) {
// Objects are too loose.
expectAssignable<Node>(node)
expectNotType<Node>(node)
expectType<number | undefined>(index)
expectAssignable<Parent | undefined>(parent)
})

type Flow = Blockquote | Heading | Paragraph
// ## String test

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Blockquote extends Parent {
type: 'blockquote'
children: Array<Flow>
}
// Knows it’s a heading and its parents.
visit(sampleTree, 'heading', function (node, index, parent) {
expectType<Heading>(node)
expectType<number | undefined>(index)
expectType<
Blockquote | FootnoteDefinition | ListItem | Root | undefined
>(parent)
})

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Heading extends Parent {
type: 'heading'
depth: number
children: Array<Phrasing>
}
// Not in tree.
visit(sampleTree, 'element', function (node, index, parent) {
expectType<never>(node)
expectType<never>(index)
expectType<never>(parent)
})

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Paragraph extends Parent {
type: 'paragraph'
children: Array<Phrasing>
}
// Implicit nodes are too loose.
visit(implicitTree, 'heading', function (node, index, parent) {
expectType<never>(node)
expectType<never>(index)
expectType<never>(parent)
})

type Phrasing = Text | Emphasis
visit(sampleTree, 'tableCell', function (node, index, parent) {
expectType<TableCell>(node)
expectType<number | undefined>(index)
expectType<Root | TableRow | undefined>(parent)
})

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Emphasis extends Parent {
type: 'emphasis'
children: Array<Phrasing>
}
// ## Props test

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface Text extends Literal {
type: 'text'
value: string
}
// Knows that headings have depth, but TS doesn’t infer the depth normally.
visit(sampleTree, {depth: 1}, function (node) {
expectType<Heading>(node)
expectType<1 | 2 | 3 | 4 | 5 | 6>(node.depth)
})

const isNode = (node: unknown): node is Node =>
typeof node === 'object' && node !== null && 'type' in node
const headingTest = (node: unknown): node is Heading =>
isNode(node) && node.type === 'heading'
const elementTest = (node: unknown): node is Element =>
isNode(node) && node.type === 'element'
// This goes fine.
visit(sampleTree, {type: 'heading'} as const, function (node) {
expectType<Heading>(node)
expectType<1 | 2 | 3 | 4 | 5 | 6>(node.depth)
})

/* Missing params. */
expectError(visit())
expectError(visit(sampleTree))
// For some reason the const goes wrong.
visit(sampleTree, {depth: 1} as const, function (node) {
// Note: something going wrong here, to do: investigate.
expectType<never>(node)
})

/* Visit without test. */
visit(sampleTree, (node, _, parent) => {
expectType<Root | Content>(node)
expectType<Extract<Root | Content, Parent> | null>(parent)
// For some reason the const goes wrong.
visit(sampleTree, {type: 'heading', depth: 1} as const, function (node) {
// Note: something going wrong here, to do: investigate.
expectType<never>(node)
})

/* Visit with type test. */
visit(sampleTree, 'heading', (node, _, parent) => {
// Function test (implicit assertion).
visit(sampleTree, isHeadingLoose, function (node) {
expectType<Nodes>(node)
})
// Function test (explicit assertion).
visit(sampleTree, isHeading, function (node) {
expectType<Heading>(node)
expectType<Root | Blockquote | null>(parent)
expectType<1 | 2 | 3 | 4 | 5 | 6>(node.depth)
})
visit(sampleTree, 'element', (node, index, parent) => {
// Not in tree.
expectType<never>(node)
expectType<never>(index)
expectType<never>(parent)
// Function test (explicit assertion).
visit(sampleTree, isHeading2, function (node) {
expectType<Heading & {depth: 2}>(node)
})
expectError(visit(sampleTree, 'heading', (_: Element) => {}))

/* Visit with object test. */
visit(sampleTree, {depth: 1}, (node) => {
expectType<Heading>(node)
// ## Combined tests
visit(sampleTree, ['heading', {depth: 1}, isHeading], function (node) {
// Unfortunately TS casts things in arrays too vague.
expectType<Root | RootContent>(node)
})
visit(sampleTree, {random: 'property'}, (node) => {
expectType<never>(node)

// To do: update to `unist-util-is` should make this work?
// visit(
// sampleTree,
// ['heading', {depth: 1}, isHeading] as const,
// function (node) {
// // Unfortunately TS casts things in arrays too vague.
// expectType<Root | RootContent>(node)
// }
// )

// ## Return type: incorrect.
// @ts-expect-error: not an action.
visit(sampleTree, function () {
return 'random'
})
visit(sampleTree, {type: 'heading', depth: '2'}, (node) => {
// Not in tree.
expectType<never>(node)
// @ts-expect-error: not a tuple: missing action.
visit(sampleTree, function () {
return [1]
})
visit(sampleTree, {tagName: 'section'}, (node) => {
// Not in tree.
expectType<never>(node)
// @ts-expect-error: not a tuple: incorrect action.
visit(sampleTree, function () {
return ['random', 1]
})
visit(sampleTree, {type: 'element', tagName: 'section'}, (node) => {
// Not in tree.
expectType<never>(node)

// ## Return type: action.
visit(sampleTree, function () {
return CONTINUE
})
visit(sampleTree, function () {
return EXIT
})
visit(sampleTree, function () {
return SKIP
})

/* Visit with function test. */
visit(sampleTree, headingTest, (node) => {
expectType<Heading>(node)
// ## Return type: index.
visit(sampleTree, function () {
return 0
})
expectError(visit(sampleTree, headingTest, (_: Element) => {}))
visit(sampleTree, elementTest, (node) => {
// Not in tree.
expectType<never>(node)
visit(sampleTree, function () {
return 1
})

/* Visit with array of tests. */
visit(sampleTree, ['heading', {depth: 1}, headingTest], (node) => {
// Unfortunately TS casts things in arrays too vague.
expectType<Root | Content>(node)
})

/* Visit returns action. */
visit(sampleTree, () => CONTINUE)
visit(sampleTree, () => EXIT)
visit(sampleTree, () => SKIP)
expectError(visit(sampleTree, () => 'random'))

/* Visit returns index. */
visit(sampleTree, () => 0)
visit(sampleTree, () => 1)

/* Visit returns tuple. */
visit(sampleTree, () => [CONTINUE, 1])
visit(sampleTree, () => [EXIT, 1])
visit(sampleTree, () => [SKIP, 1])
visit(sampleTree, () => [SKIP])
expectError(visit(sampleTree, () => [1]))
expectError(visit(sampleTree, () => ['random', 1]))

/* Should infer children from the given tree. */
visit(complexTree, (node, _, parent) => {
expectType<Root | Content>(node)
expectType<Extract<Root | Content, Parent> | null>(parent)
})

const blockquote = complexTree.children[0]
if (is<Blockquote>(blockquote, 'blockquote')) {
visit(blockquote, (node, _, parent) => {
expectType<Content>(node)
expectType<Extract<Content, Parent> | null>(parent)
// ## Return type: tuple.
visit(sampleTree, function () {
return [CONTINUE, 1]
})
visit(sampleTree, function () {
return [EXIT, 1]
})
visit(sampleTree, function () {
return [SKIP, 1]
})
visit(sampleTree, function () {
return [SKIP]
})

// ## Infer on tree
visit(sampleTree, 'tableCell', function (node) {
visit(node, function (node, _, parent) {
expectType<TableCell | PhrasingContent>(node)
expectType<
Delete | Emphasis | Link | LinkReference | Strong | TableCell | undefined
>(parent)
})
}
})

const paragraph = complexTree.children[1]
if (is<Paragraph>(paragraph, 'paragraph')) {
visit(paragraph, (node, _, parent) => {
expectType<Paragraph | Phrasing>(node)
expectType<Paragraph | Emphasis | null>(parent)
visit(sampleTree, 'definition', function (node) {
visit(node, function (node, _, parent) {
expectType<Definition>(node)
expectType<never>(parent)
})
})

const child = paragraph.children[1]
function isHeading(node: Node): node is Heading {
return node ? node.type === 'heading' : false
}

function isHeading2(node: Node): node is Heading & {depth: 2} {
return isHeading(node) && node.depth === 2
}

if (is<Emphasis>(child, 'emphasis')) {
visit(child, 'blockquote', (node, index, parent) => {
// `blockquote` does not exist in phrasing.
expectType<never>(node)
expectType<never>(index)
expectType<never>(parent)
})
}
function isHeadingLoose(node: Node) {
return node ? node.type === 'heading' : false
}
Loading