Skip to content

Commit e0f582e

Browse files
committed
Refactor to move implementation to lib/
1 parent 39273c7 commit e0f582e

File tree

7 files changed

+381
-379
lines changed

7 files changed

+381
-379
lines changed

index.js

Lines changed: 2 additions & 369 deletions
Original file line numberDiff line numberDiff line change
@@ -1,372 +1,5 @@
11
/**
2-
* @typedef {import('assert').AssertionError} AssertionError
3-
* @typedef {import('unist').Node} Node
4-
* @typedef {import('unist').Parent} Parent
5-
* @typedef {import('unist').Literal} Literal
6-
* @typedef {import('unist').Position} Position
7-
* @typedef {import('unist').Point} Point
8-
* @typedef {Node & {children: never, value: never}} _Void
9-
*
10-
* @typedef SeenErrorFields
11-
* @property {true} [__unist__]
12-
*
13-
* @typedef {Error & SeenErrorFields} SeenError
2+
* @typedef {import('./lib/index.js').AssertionError} AssertionError
143
*/
154

16-
import nodeAssert from 'node:assert'
17-
import {inspect} from './inspect.js'
18-
19-
const own = {}.hasOwnProperty
20-
21-
/**
22-
* Assert that `tree` is a valid unist node.
23-
*
24-
* If `node` is a parent, all children will be asserted too.
25-
*
26-
* @param {unknown} [tree]
27-
* Thing to assert.
28-
* @param {Parent | null | undefined} [parent]
29-
* Optional, valid parent.
30-
* @returns {asserts tree is Node}
31-
* Whether `tree` (and its descendants) are valid nodes.
32-
* @throws {AssertionError}
33-
* When `tree` (or its descendants) is not a node.
34-
*/
35-
export function assert(tree, parent) {
36-
return wrap(assertNode)(tree, parent)
37-
}
38-
39-
/**
40-
* Assert that `tree` is a valid unist parent.
41-
*
42-
* All children will be asserted too.
43-
*
44-
* @param {unknown} [tree]
45-
* Thing to assert.
46-
* @param {Parent | null | undefined} [parent]
47-
* Optional, valid parent.
48-
* @returns {asserts tree is Parent}
49-
* Whether `tree` is a parent and its descendants are valid nodes.
50-
* @throws {AssertionError}
51-
* When `tree` is not a parent or its descendants are not nodes.
52-
*/
53-
export function parent(tree, parent) {
54-
return wrap(assertParent)(tree, parent)
55-
}
56-
57-
/**
58-
* Assert that `node` is a valid unist literal.
59-
*
60-
* @param {unknown} [node]
61-
* Thing to assert.
62-
* @param {Parent | null | undefined} [parent]
63-
* Optional, valid parent.
64-
* @returns {asserts node is Literal}
65-
* Whether `node` is a literal.
66-
* @throws {AssertionError}
67-
* When `node` is not a literal.
68-
*/
69-
export function literal(node, parent) {
70-
return wrap(assertLiteral)(node, parent)
71-
}
72-
73-
/**
74-
* Assert that `node` is a valid void node.
75-
*
76-
* @param {unknown} [node]
77-
* Thing to assert.
78-
* @param {Parent | null | undefined} [parent]
79-
* Optional, valid parent.
80-
* @returns {asserts node is _Void}
81-
* Whether `node` is a node but neither parent nor literal.
82-
* @throws {AssertionError}
83-
* When `node` is not a node, a parent, or a literal.
84-
*/
85-
export function _void(node, parent) {
86-
return wrap(assertVoid)(node, parent)
87-
}
88-
89-
// Identifier to check if a value is seen.
90-
const ID = '__unist__'
91-
92-
// List of specced properties.
93-
const defined = new Set(['type', 'value', 'children', 'position'])
94-
95-
/**
96-
* Wrapper that adds the current node (and parent, if available) to error
97-
* messages.
98-
*
99-
* @template {Node} T
100-
* Node type.
101-
* @param {(node?: any, parent?: Parent | null | undefined) => asserts node is T} fn
102-
* Custom assertion.
103-
* @returns {(node?: any, parent?: Parent | null | undefined) => asserts node is T}
104-
* Assertion.
105-
*/
106-
export function wrap(fn) {
107-
return wrapped
108-
109-
/**
110-
* @param {unknown} node
111-
* Thing to check.
112-
* @param {Parent | null | undefined} [parent]
113-
* Optional, valid parent.
114-
* @throws {AssertionError}
115-
* Whether `node` is a node but neither parent nor literal.
116-
* @returns {void}
117-
* Nothing.
118-
*/
119-
function wrapped(node, parent) {
120-
try {
121-
fn(node, parent)
122-
} catch (error) {
123-
const exception = /** @type {SeenError} */ (error)
124-
if (!own.call(exception, ID)) {
125-
exception[ID] = true
126-
exception.message += ': `' + view(node) + '`'
127-
if (parent) exception.message += ' in `' + view(parent) + '`'
128-
}
129-
130-
throw error
131-
}
132-
}
133-
}
134-
135-
/**
136-
* Assert that `node` is a valid unist parent.
137-
*
138-
* All children will be asserted too.
139-
*
140-
* @param {unknown} node
141-
* Thing to assert.
142-
* @returns {asserts node is Node}
143-
* Whether `node` (and its descendants) are valid nodes.
144-
* @throws {AssertionError}
145-
* When `node` (or its descendants) is not a node.
146-
*/
147-
function assertNode(node) {
148-
let index = -1
149-
150-
nodeAssert.ok(
151-
node && typeof node === 'object' && !Array.isArray(node),
152-
'node should be an object'
153-
)
154-
155-
nodeAssert.ok(own.call(node, 'type'), 'node should have a type')
156-
nodeAssert.strictEqual(
157-
// @ts-expect-error Looks like an indexed object.
158-
typeof node.type,
159-
'string',
160-
'`type` should be a string'
161-
)
162-
// @ts-expect-error Looks like an indexed object.
163-
nodeAssert.notStrictEqual(node.type, '', '`type` should not be empty')
164-
165-
// @ts-expect-error Looks like an indexed object.
166-
if (node.value !== null && node.value !== undefined) {
167-
nodeAssert.strictEqual(
168-
// @ts-expect-error Looks like an indexed object.
169-
typeof node.value,
170-
'string',
171-
'`value` should be a string'
172-
)
173-
}
174-
175-
// @ts-expect-error Looks like an indexed object.
176-
position(node.position)
177-
178-
/** @type {string} */
179-
let key
180-
181-
for (key in node) {
182-
if (!defined.has(key)) {
183-
/** @type {unknown} */
184-
// @ts-expect-error: hush.
185-
const value = node[key]
186-
vanilla(key, value)
187-
}
188-
}
189-
190-
// @ts-expect-error Looks like an indexed object.
191-
if (node.children !== null && node.children !== undefined) {
192-
/** @type {Parent} */
193-
// @ts-expect-error Looks like parent.
194-
const parent = node
195-
nodeAssert.ok(
196-
Array.isArray(parent.children),
197-
'`children` should be an array'
198-
)
199-
index = -1
200-
201-
while (++index < parent.children.length) {
202-
assert(parent.children[index], parent)
203-
}
204-
}
205-
}
206-
207-
/**
208-
* Assert `value` (which lives at `key`) can be stringified and re-parsed to the
209-
* same (deep) value.
210-
*
211-
* @param {string} key
212-
* Name of field.
213-
* @param {unknown} value
214-
* Value of field.
215-
*/
216-
function vanilla(key, value) {
217-
try {
218-
nodeAssert.deepStrictEqual(value, JSON.parse(JSON.stringify(value)))
219-
} catch {
220-
nodeAssert.fail('non-specced property `' + key + '` should be JSON')
221-
}
222-
}
223-
224-
/**
225-
* Stringify a value to inspect it.
226-
*
227-
* Tries `JSON.stringify()`, and if that fails uses `String()` instead.
228-
*
229-
* @param {unknown} value
230-
* Anything (should be JSON).
231-
* @returns {string}
232-
* User-visible preresentation.
233-
*/
234-
function view(value) {
235-
try {
236-
return inspect(value)
237-
/* c8 ignore next 3 */
238-
} catch {
239-
return String(value)
240-
}
241-
}
242-
243-
/**
244-
* Assert that `node` is a valid unist parent.
245-
*
246-
* All children will be asserted too.
247-
*
248-
* @param {Node} node
249-
* Thing to assert.
250-
* @returns {asserts node is Parent}
251-
* Whether `node` is a parent and its descendants are valid nodes.
252-
* @throws {AssertionError}
253-
* When `node` is not a parent or its descendants are not nodes.
254-
*/
255-
function assertParent(node) {
256-
assertNode(node)
257-
258-
nodeAssert.strictEqual(
259-
'value' in node,
260-
false,
261-
'parent should not have `value`'
262-
)
263-
nodeAssert.ok('children' in node, 'parent should have `children`')
264-
}
265-
266-
/**
267-
* Assert that `node` is a valid unist literal.
268-
*
269-
* @param {unknown} [node]
270-
* Thing to assert.
271-
* @returns {asserts node is Literal}
272-
* Whether `node` is a literal.
273-
* @throws {AssertionError}
274-
* When `node` is not a literal.
275-
*/
276-
function assertLiteral(node) {
277-
assertNode(node)
278-
279-
nodeAssert.strictEqual(
280-
'children' in node,
281-
false,
282-
'literal should not have `children`'
283-
)
284-
nodeAssert.ok('value' in node, 'literal should have `value`')
285-
}
286-
287-
/**
288-
* Assert that `node` is a valid void node.
289-
*
290-
* @param {unknown} [node]
291-
* Thing to assert.
292-
* @returns {asserts node is _Void}
293-
* Whether `node` is a node but neither parent nor literal.
294-
* @throws {AssertionError}
295-
* When `node` is not a node, a parent, or a literal.
296-
*/
297-
function assertVoid(node) {
298-
assertNode(node)
299-
300-
nodeAssert.strictEqual('value' in node, false, 'void should not have `value`')
301-
nodeAssert.strictEqual(
302-
'children' in node,
303-
false,
304-
'void should not have `children`'
305-
)
306-
}
307-
308-
/**
309-
* Assert that `position` is a unist position.
310-
*
311-
* @param {unknown} position
312-
* Thing to assert.
313-
* @returns {asserts position is Position}
314-
* Whether `position` is a unist position.
315-
* @throws {AssertionError}
316-
* When `position` is not a position.
317-
*/
318-
function position(position) {
319-
if (position !== null && position !== undefined) {
320-
nodeAssert.ok(
321-
typeof position === 'object' && position === Object(position),
322-
'`position` should be an object'
323-
)
324-
325-
// @ts-expect-error: indexable.
326-
point(position.start, 'position.start')
327-
// @ts-expect-error: indexable.
328-
point(position.end, 'position.end')
329-
}
330-
}
331-
332-
/**
333-
* Assert `point` is a unist point.
334-
*
335-
* @param {unknown} point
336-
* Thing to assert.
337-
* @param {string} label
338-
* Whether `point` is a unist point.
339-
* @returns {asserts point is Point}
340-
* When `point` is not a point.
341-
*/
342-
function point(point, label) {
343-
if (point !== null && point !== undefined) {
344-
nodeAssert.ok(
345-
typeof point === 'object' && point === Object(point),
346-
'`' + label + '` should be an object'
347-
)
348-
349-
if ('line' in point && point.line !== null && point.line !== undefined) {
350-
nodeAssert.ok(
351-
typeof point.line === 'number',
352-
'`' + label + '` should have numeric `line`'
353-
)
354-
nodeAssert.ok(point.line >= 1, '`' + label + '.line` should be gte `1`')
355-
}
356-
357-
if (
358-
'column' in point &&
359-
point.column !== null &&
360-
point.column !== undefined
361-
) {
362-
nodeAssert.ok(
363-
typeof point.column === 'number',
364-
'`' + label + '` should have numeric `column`'
365-
)
366-
nodeAssert.ok(
367-
point.column >= 1,
368-
'`' + label + '.column` should be gte `1`'
369-
)
370-
}
371-
}
372-
}
5+
export {_void, assert, literal, parent, wrap} from './lib/index.js'

index.test-d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {expectType, expectNotType} from 'tsd'
2-
import {type Node, type Parent} from 'unist'
2+
import type {Node, Parent} from 'unist'
33
import {assert, parent} from './index.js'
44

55
const emptyNode = {type: 'a'}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy