No flags found
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
8b10d91
... +20 ...
b938821
Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.
e.g., #unittest #integration
#production #enterprise
#frontend #backend
1 | - | 'use strict' |
|
1 | + | /** |
|
2 | + | * @typedef {import('unist').Node} Node |
|
3 | + | * @typedef {import('unist').Parent} Parent |
|
4 | + | * |
|
5 | + | * @typedef {string} Type |
|
6 | + | * @typedef {Object<string, unknown>} Props |
|
7 | + | * |
|
8 | + | * @typedef {null|undefined|Type|Props|TestFunctionAnything|Array.<Type|Props|TestFunctionAnything>} Test |
|
9 | + | */ |
|
2 | 10 | ||
3 | - | var convert = require('./convert') |
|
11 | + | /** |
|
12 | + | * Check if a node passes a test |
|
13 | + | * |
|
14 | + | * @callback TestFunctionAnything |
|
15 | + | * @param {Node} node |
|
16 | + | * @param {number|null|undefined} [index] |
|
17 | + | * @param {Parent|null|undefined} [parent] |
|
18 | + | * @returns {boolean|void} |
|
19 | + | */ |
|
4 | 20 | ||
5 | - | module.exports = is |
|
21 | + | /** |
|
22 | + | * Check if a node passes a certain node test |
|
23 | + | * |
|
24 | + | * @template {Node} X |
|
25 | + | * @callback TestFunctionPredicate |
|
26 | + | * @param {Node} node |
|
27 | + | * @param {number|null|undefined} [index] |
|
28 | + | * @param {Parent|null|undefined} [parent] |
|
29 | + | * @returns {node is X} |
|
30 | + | */ |
|
6 | 31 | ||
7 | - | is.convert = convert |
|
32 | + | /** |
|
33 | + | * @callback AssertAnything |
|
34 | + | * @param {unknown} [node] |
|
35 | + | * @param {number|null|undefined} [index] |
|
36 | + | * @param {Parent|null|undefined} [parent] |
|
37 | + | * @returns {boolean} |
|
38 | + | */ |
|
8 | 39 | ||
9 | - | // Assert if `test` passes for `node`. |
|
10 | - | // When a `parent` node is known the `index` of node should also be given. |
|
11 | - | function is(node, test, index, parent, context) { |
|
12 | - | var check = convert(test) |
|
40 | + | /** |
|
41 | + | * Check if a node passes a certain node test |
|
42 | + | * |
|
43 | + | * @template {Node} Y |
|
44 | + | * @callback AssertPredicate |
|
45 | + | * @param {unknown} [node] |
|
46 | + | * @param {number|null|undefined} [index] |
|
47 | + | * @param {Parent|null|undefined} [parent] |
|
48 | + | * @returns {node is Y} |
|
49 | + | */ |
|
13 | 50 | ||
14 | - | if ( |
|
15 | - | index != null && |
|
16 | - | (typeof index !== 'number' || index < 0 || index === Infinity) |
|
17 | - | ) { |
|
18 | - | throw new Error('Expected positive finite index') |
|
51 | + | /** |
|
52 | + | * Check if a node passes a test. |
|
53 | + | * When a `parent` node is known the `index` of node should also be given. |
|
54 | + | * |
|
55 | + | * @param node |
|
56 | + | * Node to check, can be anything. |
|
57 | + | * @param test |
|
58 | + | * * When nullish, checks if `node` is a `Node`. |
|
59 | + | * * When `string`, works like passing `(node) => node.type === test`. |
|
60 | + | * * When `function` checks if function passed the node is true. |
|
61 | + | * * When `object`, checks that all keys in test are in node, and that they have (strictly) equal values. |
|
62 | + | * * When `array`, checks any one of the subtests pass. |
|
63 | + | * @param index |
|
64 | + | * Position of `node` in `parent`, must be a number if `parent` is also given. |
|
65 | + | * @param parent |
|
66 | + | * Parent of `node`, must be given if `index` is also given. |
|
67 | + | * @param context |
|
68 | + | * Context object to invoke `test` with, optional |
|
69 | + | * @returns |
|
70 | + | * Whether test passed and `node` is a `Node` (object with `type` set to |
|
71 | + | * non-empty `string`). |
|
72 | + | */ |
|
73 | + | export const is = |
|
74 | + | /** |
|
75 | + | * @type {( |
|
76 | + | * (<ExplicitNode extends Node>(node: unknown, test: ExplicitNode['type']|Partial<ExplicitNode>|TestFunctionPredicate<ExplicitNode>|Array.<ExplicitNode['type']|Partial<ExplicitNode>|TestFunctionPredicate<ExplicitNode>>, index: number, parent: Parent, context?: unknown) => node is ExplicitNode) & |
|
77 | + | * (<ExplicitNode extends Node>(node: unknown, test: ExplicitNode['type']|Partial<ExplicitNode>|TestFunctionPredicate<ExplicitNode>|Array.<ExplicitNode['type']|Partial<ExplicitNode>|TestFunctionPredicate<ExplicitNode>>, index?: null|undefined, parent?: null|undefined, context?: unknown) => node is ExplicitNode) & |
|
78 | + | * ((node: unknown, test: Test, index: number, parent: Parent, context?: unknown) => boolean) & |
|
79 | + | * ((node?: unknown, test?: Test, index?: null|undefined, parent?: null|undefined, context?: unknown) => boolean) |
|
80 | + | * )} |
|
81 | + | */ |
|
82 | + | ( |
|
83 | + | /** |
|
84 | + | * @param {unknown} [node] |
|
85 | + | * @param {Test} [test] |
|
86 | + | * @param {number|null|undefined} [index] |
|
87 | + | * @param {Parent|null|undefined} [parent] |
|
88 | + | * @param {unknown} [context] |
|
89 | + | * @returns {boolean} |
|
90 | + | */ |
|
91 | + | // eslint-disable-next-line max-params |
|
92 | + | function is(node, test, index, parent, context) { |
|
93 | + | const check = convert(test) |
|
94 | + | ||
95 | + | if ( |
|
96 | + | index !== undefined && |
|
97 | + | index !== null && |
|
98 | + | (typeof index !== 'number' || |
|
99 | + | index < 0 || |
|
100 | + | index === Number.POSITIVE_INFINITY) |
|
101 | + | ) { |
|
102 | + | throw new Error('Expected positive finite index') |
|
103 | + | } |
|
104 | + | ||
105 | + | if ( |
|
106 | + | parent !== undefined && |
|
107 | + | parent !== null && |
|
108 | + | (!is(parent) || !parent.children) |
|
109 | + | ) { |
|
110 | + | throw new Error('Expected parent node') |
|
111 | + | } |
|
112 | + | ||
113 | + | if ( |
|
114 | + | (parent === undefined || parent === null) !== |
|
115 | + | (index === undefined || index === null) |
|
116 | + | ) { |
|
117 | + | throw new Error('Expected both parent and index') |
|
118 | + | } |
|
119 | + | ||
120 | + | // @ts-expect-error Looks like a node. |
|
121 | + | return node && node.type && typeof node.type === 'string' |
|
122 | + | ? Boolean(check.call(context, node, index, parent)) |
|
123 | + | : false |
|
124 | + | } |
|
125 | + | ) |
|
126 | + | ||
127 | + | export const convert = |
|
128 | + | /** |
|
129 | + | * @type {( |
|
130 | + | * (<ExplicitNode extends Node>(test: ExplicitNode['type']|Partial<ExplicitNode>|TestFunctionPredicate<ExplicitNode>) => AssertPredicate<ExplicitNode>) & |
|
131 | + | * ((test?: Test) => AssertAnything) |
|
132 | + | * )} |
|
133 | + | */ |
|
134 | + | ( |
|
135 | + | /** |
|
136 | + | * Generate an assertion from a check. |
|
137 | + | * @param {Test} [test] |
|
138 | + | * When nullish, checks if `node` is a `Node`. |
|
139 | + | * When `string`, works like passing `function (node) {return node.type === test}`. |
|
140 | + | * When `function` checks if function passed the node is true. |
|
141 | + | * When `object`, checks that all keys in test are in node, and that they have (strictly) equal values. |
|
142 | + | * When `array`, checks any one of the subtests pass. |
|
143 | + | * @returns {AssertAnything} |
|
144 | + | */ |
|
145 | + | function (test) { |
|
146 | + | if (test === undefined || test === null) { |
|
147 | + | return ok |
|
148 | + | } |
|
149 | + | ||
150 | + | if (typeof test === 'string') { |
|
151 | + | return typeFactory(test) |
|
152 | + | } |
|
153 | + | ||
154 | + | if (typeof test === 'object') { |
|
155 | + | return Array.isArray(test) ? anyFactory(test) : propsFactory(test) |
|
156 | + | } |
|
157 | + | ||
158 | + | if (typeof test === 'function') { |
|
159 | + | return castFactory(test) |
|
160 | + | } |
|
161 | + | ||
162 | + | throw new Error('Expected function, string, or object as test') |
|
163 | + | } |
|
164 | + | ) |
|
165 | + | /** |
|
166 | + | * @param {Array.<Type|Props|TestFunctionAnything>} tests |
|
167 | + | * @returns {AssertAnything} |
|
168 | + | */ |
|
169 | + | function anyFactory(tests) { |
|
170 | + | /** @type {Array.<AssertAnything>} */ |
|
171 | + | const checks = [] |
|
172 | + | let index = -1 |
|
173 | + | ||
174 | + | while (++index < tests.length) { |
|
175 | + | checks[index] = convert(tests[index]) |
|
176 | + | } |
|
177 | + | ||
178 | + | return castFactory(any) |
|
179 | + | ||
180 | + | /** |
|
181 | + | * @this {unknown} |
|
182 | + | * @param {unknown[]} parameters |
|
183 | + | * @returns {boolean} |
|
184 | + | */ |
|
185 | + | function any(...parameters) { |
|
186 | + | let index = -1 |
|
187 | + | ||
188 | + | while (++index < checks.length) { |
|
189 | + | if (checks[index].call(this, ...parameters)) return true |
|
190 | + | } |
|
191 | + | ||
192 | + | return false |
|
19 | 193 | } |
|
194 | + | } |
|
195 | + | ||
196 | + | /** |
|
197 | + | * Utility to assert each property in `test` is represented in `node`, and each |
|
198 | + | * values are strictly equal. |
|
199 | + | * |
|
200 | + | * @param {Props} check |
|
201 | + | * @returns {AssertAnything} |
|
202 | + | */ |
|
203 | + | function propsFactory(check) { |
|
204 | + | return castFactory(all) |
|
20 | 205 | ||
21 | - | if (parent != null && (!is(parent) || !parent.children)) { |
|
22 | - | throw new Error('Expected parent node') |
|
206 | + | /** |
|
207 | + | * @param {Node} node |
|
208 | + | * @returns {boolean} |
|
209 | + | */ |
|
210 | + | function all(node) { |
|
211 | + | /** @type {string} */ |
|
212 | + | let key |
|
213 | + | ||
214 | + | for (key in check) { |
|
215 | + | // @ts-expect-error: hush, it sure works as an index. |
|
216 | + | if (node[key] !== check[key]) return false |
|
217 | + | } |
|
218 | + | ||
219 | + | return true |
|
23 | 220 | } |
|
221 | + | } |
|
24 | 222 | ||
25 | - | if ((parent == null) !== (index == null)) { |
|
26 | - | throw new Error('Expected both parent and index') |
|
223 | + | /** |
|
224 | + | * Utility to convert a string into a function which checks a given node’s type |
|
225 | + | * for said string. |
|
226 | + | * |
|
227 | + | * @param {Type} check |
|
228 | + | * @returns {AssertAnything} |
|
229 | + | */ |
|
230 | + | function typeFactory(check) { |
|
231 | + | return castFactory(type) |
|
232 | + | ||
233 | + | /** |
|
234 | + | * @param {Node} node |
|
235 | + | */ |
|
236 | + | function type(node) { |
|
237 | + | return node && node.type === check |
|
238 | + | } |
|
239 | + | } |
|
240 | + | ||
241 | + | /** |
|
242 | + | * Utility to convert a string into a function which checks a given node’s type |
|
243 | + | * for said string. |
|
244 | + | * @param {TestFunctionAnything} check |
|
245 | + | * @returns {AssertAnything} |
|
246 | + | */ |
|
247 | + | function castFactory(check) { |
|
248 | + | return assertion |
|
249 | + | ||
250 | + | /** |
|
251 | + | * @this {unknown} |
|
252 | + | * @param {Array.<unknown>} parameters |
|
253 | + | * @returns {boolean} |
|
254 | + | */ |
|
255 | + | function assertion(...parameters) { |
|
256 | + | // @ts-expect-error: spreading is fine. |
|
257 | + | return Boolean(check.call(this, ...parameters)) |
|
27 | 258 | } |
|
259 | + | } |
|
28 | 260 | ||
29 | - | return node && node.type && typeof node.type === 'string' |
|
30 | - | ? Boolean(check.call(context, node, index, parent)) |
|
31 | - | : false |
|
261 | + | // Utility to return true. |
|
262 | + | function ok() { |
|
263 | + | return true |
|
32 | 264 | } |
Files | Coverage |
---|---|
index.js | 100.00% |
Project Totals (1 files) | 100.00% |
b938821
06def74
9048259
37672e7
f7c1d67
27b28da
9dc1e50
bfafa4b
fc608c6
65a22a2
374dd25
2f3214b
f660b18
f78c229
131ee3d
d321ae7
2bb1e0e
2698c0a
9aa62ed
f7459ff
b44f1e9
#11
8b10d91