Skip to content

Commit 25eea24

Browse files
committed
Add JSDoc based types
1 parent 37efcc5 commit 25eea24

11 files changed

+136
-122
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
*.d.ts
12
coverage/
23
node_modules/

.prettierignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
coverage/
2-
*.json
32
*.md

index.js

+77-32
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,87 @@
1+
/**
2+
* @typedef {import('unist').Node} Node
3+
* @typedef {import('unist').Parent} Parent
4+
*
5+
* @typedef {import('unist-util-is').Type} Type
6+
* @typedef {import('unist-util-is').Props} Props
7+
* @typedef {import('unist-util-is').TestFunctionAnything} TestFunctionAnything
8+
*/
9+
10+
/**
11+
* @typedef {Object} RemoveOptions
12+
* @property {boolean} [cascade] Whether to drop parent nodes if they had children, but all their children were filtered out test
13+
*/
14+
115
import {convert} from 'unist-util-is'
216

3-
export function remove(tree, options, test) {
4-
var is = convert(test || options)
5-
var cascade =
6-
options.cascade === undefined || options.cascade === null
7-
? true
8-
: options.cascade
17+
/** @type {Array.<Node>} */
18+
var empty = []
919

10-
return preorder(tree, null, null)
20+
export var remove =
21+
/**
22+
* @type {(
23+
* (<T extends Node>(node: T, options: RemoveOptions, test: Type|Props|TestFunctionAnything|Array<Type|Props|TestFunctionAnything>) => T|null) &
24+
* (<T extends Node>(node: T, test: Type|Props|TestFunctionAnything|Array<Type|Props|TestFunctionAnything>) => T|null)
25+
* )}
26+
*/
27+
(
28+
/**
29+
* Mutate the given tree by removing all nodes that pass `test`.
30+
* The tree is walked in preorder (NLR), visiting the node itself, then its head, etc.
31+
*
32+
* @param {Node} tree Tree to filter
33+
* @param {RemoveOptions} options Whether to drop parent nodes if they had children, but all their children were filtered out. Default is `{cascade: true}`
34+
* @param {Type|Props|TestFunctionAnything|Array<Type|Props|TestFunctionAnything>} test is-compatible test (such as a type)
35+
* @returns {Node|null}
36+
*/
37+
function (tree, options, test) {
38+
var is = convert(test || options)
39+
var cascade =
40+
options.cascade === undefined || options.cascade === null
41+
? true
42+
: options.cascade
1143

12-
// Check and remove nodes recursively in preorder.
13-
// For each composite node, modify its children array in-place.
14-
function preorder(node, index, parent) {
15-
var children = node.children
16-
var childIndex = -1
17-
var position = 0
44+
return preorder(tree, null, null)
1845

19-
if (is(node, index, parent)) {
20-
return null
21-
}
46+
/**
47+
* Check and remove nodes recursively in preorder.
48+
* For each composite node, modify its children array in-place.
49+
*
50+
* @param {Node} node
51+
* @param {number|null} index
52+
* @param {Parent|null} parent
53+
* @returns {Node|null}
54+
*/
55+
function preorder(node, index, parent) {
56+
/** @type {Array.<Node>} */
57+
// @ts-ignore looks like a parent.
58+
var children = node.children || empty
59+
var childIndex = -1
60+
var position = 0
2261

23-
if (children && children.length > 0) {
24-
// Move all living children to the beginning of the children array.
25-
while (++childIndex < children.length) {
26-
if (preorder(children[childIndex], childIndex, node)) {
27-
children[position++] = children[childIndex]
62+
if (is(node, index, parent)) {
63+
return null
2864
}
29-
}
3065

31-
// Cascade delete.
32-
if (cascade && !position) {
33-
return null
34-
}
66+
if (children.length > 0) {
67+
// Move all living children to the beginning of the children array.
68+
while (++childIndex < children.length) {
69+
// @ts-ignore looks like a parent.
70+
if (preorder(children[childIndex], childIndex, node)) {
71+
children[position++] = children[childIndex]
72+
}
73+
}
3574

36-
// Drop other nodes.
37-
children.length = position
38-
}
75+
// Cascade delete.
76+
if (cascade && !position) {
77+
return null
78+
}
79+
80+
// Drop other nodes.
81+
children.length = position
82+
}
3983

40-
return node
41-
}
42-
}
84+
return node
85+
}
86+
}
87+
)

package.json

+17-6
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,36 @@
3232
"sideEffects": false,
3333
"type": "module",
3434
"main": "index.js",
35-
"types": "types/index.d.ts",
35+
"types": "index.d.ts",
3636
"files": [
37-
"index.js",
38-
"types/index.d.ts"
37+
"index.d.ts",
38+
"index.js"
3939
],
4040
"dependencies": {
41+
"@types/unist": "^2.0.0",
4142
"unist-util-is": "^5.0.0"
4243
},
4344
"devDependencies": {
45+
"@types/tape": "^4.0.0",
4446
"c8": "^7.0.0",
45-
"dtslint": "^4.0.0",
46-
"nyc": "^15.0.0",
4747
"prettier": "^2.0.0",
4848
"remark-cli": "^9.0.0",
4949
"remark-preset-wooorm": "^8.0.0",
50+
"rimraf": "^3.0.0",
5051
"tape": "^5.0.0",
52+
"type-coverage": "^2.0.0",
53+
"typescript": "^4.0.0",
5154
"unist-builder": "^3.0.0",
5255
"xo": "^0.38.0"
5356
},
5457
"scripts": {
58+
"prepack": "npm run build && npm run format",
59+
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
5560
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
5661
"test-api": "node test.js",
5762
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test.js",
5863
"test-types": "dtslint types",
59-
"test": "npm run format && npm run test-coverage && npm run test-types"
64+
"test": "npm run build && npm run format && npm run test-coverage"
6065
},
6166
"prettier": {
6267
"tabWidth": 2,
@@ -69,6 +74,7 @@
6974
"xo": {
7075
"prettier": true,
7176
"rules": {
77+
"import/no-mutable-exports": "off",
7278
"no-var": "off",
7379
"prefer-arrow-callback": "off"
7480
}
@@ -77,5 +83,10 @@
7783
"plugins": [
7884
"preset-wooorm"
7985
]
86+
},
87+
"typeCoverage": {
88+
"atLeast": 100,
89+
"detail": true,
90+
"strict": true
8091
}
8192
}

readme.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Yields: (note the parent of `5` is also removed, due to `options.cascade`)
6363
This package exports the following identifiers: `remove`.
6464
There is no default export.
6565

66-
### `remove(tree[, options][, test])`
66+
### `remove(tree[, options], test)`
6767

6868
Mutate the given [tree][] by removing all nodes that pass `test`.
6969
The tree is walked in [preorder][] (NLR), visiting the node itself, then its
@@ -76,8 +76,7 @@ The tree is walked in [preorder][] (NLR), visiting the node itself, then its
7676
* `options.cascade` (`boolean`, default: `true`)
7777
— Whether to drop parent nodes if they had children, but all their children
7878
were filtered out
79-
* `test` ([`Test`][is], optional) — [`is`][is]-compatible test (such as a
80-
[type][])
79+
* `test` ([`Test`][is]) — [`is`][is]-compatible test (such as a [type][])
8180

8281
###### Returns
8382

test.js

+24
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/**
2+
* @typedef {import('unist').Node} Node
3+
* @typedef {import('unist').Parent} Parent
4+
*
5+
* @typedef {import('unist-util-is').Type} Type
6+
* @typedef {import('unist-util-is').Props} Props
7+
* @typedef {import('unist-util-is').TestFunctionAnything} TestFunctionAnything
8+
*/
9+
110
import test from 'tape'
211
import {u} from 'unist-builder'
312
import {remove} from './index.js'
@@ -32,6 +41,10 @@ test('should remove nodes with children', function (t) {
3241

3342
t.end()
3443

44+
/**
45+
* @param {Node} node
46+
* @returns {boolean}
47+
*/
3548
function test(node) {
3649
return node === first
3750
}
@@ -48,6 +61,7 @@ test('should return `null` if root node is removed', function (t) {
4861
test('should cascade-remove parent nodes', function (t) {
4962
var tree = u('root', [u('node', [u('leaf', '1')]), u('leaf', '2')])
5063
var children = tree.children
64+
// @ts-ignore it exists!
5165
var first = children[0].children[0]
5266
var last = children[1]
5367

@@ -60,6 +74,10 @@ test('should cascade-remove parent nodes', function (t) {
6074

6175
t.end()
6276

77+
/**
78+
* @param {Node} node
79+
* @returns {boolean}
80+
*/
6381
function test(node) {
6482
return node === first
6583
}
@@ -104,6 +122,10 @@ test('should support function tests', function (t) {
104122

105123
t.end()
106124

125+
/**
126+
* @param {Node} node
127+
* @returns {boolean}
128+
*/
107129
function test(node) {
108130
return node.value === '1'
109131
}
@@ -123,6 +145,7 @@ test('opts.cascade = false', function (t) {
123145
var tree = u('root', [u('node', [u('leaf', '1')]), u('leaf', '2')])
124146
var siblings = tree.children
125147
var node = siblings[0]
148+
// @ts-ignore it exists!
126149
var children = node.children
127150

128151
var next = remove(tree, {cascade: false}, 'leaf')
@@ -131,6 +154,7 @@ test('opts.cascade = false', function (t) {
131154
t.deepEqual(tree, u('root', [u('node', [])]))
132155
t.equal(tree.children, siblings)
133156
t.equal(tree.children[0], node)
157+
// @ts-ignore it exists!
134158
t.equal(tree.children[0].children, children)
135159

136160
t.end()

tsconfig.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"include": ["*.js"],
3+
"compilerOptions": {
4+
"target": "ES2020",
5+
"lib": ["ES2020"],
6+
"module": "ES2020",
7+
"moduleResolution": "node",
8+
"allowJs": true,
9+
"checkJs": true,
10+
"declaration": true,
11+
"emitDeclarationOnly": true,
12+
"allowSyntheticDefaultImports": true,
13+
"skipLibCheck": true
14+
}
15+
}

types/index.d.ts

-38
This file was deleted.

types/test.ts

-19
This file was deleted.

types/tsconfig.json

-14
This file was deleted.

types/tslint.json

-9
This file was deleted.

0 commit comments

Comments
 (0)