From 7fe1fb7d285a78b8905031743aef75ad55ca19ac Mon Sep 17 00:00:00 2001 From: Lexus Drumgold Date: Mon, 18 Mar 2024 23:33:53 -0400 Subject: [PATCH] feat(internal): utilities Signed-off-by: Lexus Drumgold --- .dictionary.txt | 1 + package.json | 3 ++ src/utils/__tests__/nodelike.spec.ts | 20 ++++++++++ src/utils/__tests__/nodename.spec.ts | 55 ++++++++++++++++++++++++++ src/utils/__tests__/parentlike.spec.ts | 27 +++++++++++++ src/utils/index.ts | 8 ++++ src/utils/nodelike.ts | 24 +++++++++++ src/utils/nodename.ts | 37 +++++++++++++++++ src/utils/parentlike.ts | 24 +++++++++++ yarn.lock | 13 +++++- 10 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 src/utils/__tests__/nodelike.spec.ts create mode 100644 src/utils/__tests__/nodename.spec.ts create mode 100644 src/utils/__tests__/parentlike.spec.ts create mode 100644 src/utils/index.ts create mode 100644 src/utils/nodelike.ts create mode 100644 src/utils/nodename.ts create mode 100644 src/utils/parentlike.ts diff --git a/.dictionary.txt b/.dictionary.txt index 4f87aaf..05fead7 100644 --- a/.dictionary.txt +++ b/.dictionary.txt @@ -31,4 +31,5 @@ unstub vates vfile vitest +xast yarnrc diff --git a/package.json b/package.json index e3576b8..3e9d45a 100644 --- a/package.json +++ b/package.json @@ -93,11 +93,13 @@ "@html-eslint/parser": "0.24.0", "@types/chai": "4.3.12", "@types/eslint": "8.56.5", + "@types/hast": "3.0.4", "@types/is-ci": "3.0.4", "@types/mdast": "4.0.3", "@types/node": "20.11.28", "@types/node-notifier": "8.0.5", "@types/unist": "3.0.2", + "@types/xast": "2.0.4", "@typescript-eslint/eslint-plugin": "7.2.0", "@typescript-eslint/parser": "7.2.0", "@vates/toggle-scripts": "1.0.0", @@ -155,6 +157,7 @@ } }, "resolutions": { + "@types/hast": "3.0.4", "@types/unist": "3.0.2", "chai": "5.1.0" }, diff --git a/src/utils/__tests__/nodelike.spec.ts b/src/utils/__tests__/nodelike.spec.ts new file mode 100644 index 0000000..e94b114 --- /dev/null +++ b/src/utils/__tests__/nodelike.spec.ts @@ -0,0 +1,20 @@ +/** + * @file Unit Tests - nodelike + * @module unist-util-visit/utils/tests/unit/nodelike + */ + +import testSubject from '../nodelike' + +describe('unit:utils/nodelike', () => { + it('should return false if value is not curly-braced object', () => { + expect(testSubject([])).to.be.false + }) + + it('should return false if value.type is invalid', () => { + expect(testSubject({ type: '' })).to.be.false + }) + + it('should return true if value is shaped like a node', () => { + expect(testSubject({ type: 'nothing' })).to.be.true + }) +}) diff --git a/src/utils/__tests__/nodename.spec.ts b/src/utils/__tests__/nodename.spec.ts new file mode 100644 index 0000000..6722e98 --- /dev/null +++ b/src/utils/__tests__/nodename.spec.ts @@ -0,0 +1,55 @@ +/** + * @file Unit Tests - nodename + * @module unist-util-visit/utils/tests/unit/nodename + */ + +import type * as hast from 'hast' +import type * as xast from 'xast' +import testSubject from '../nodename' + +describe('unit:utils/nodename', () => { + it('should return null if node does not have display name', () => { + expect(testSubject({ type: 'break' })).to.be.null + }) + + describe('node.name', () => { + let node: xast.Instruction + + beforeAll(() => { + node = { + name: 'xml', + type: 'instruction', + value: 'version="1.0" encoding="UTF-8"' + } + }) + + it('should return node.name if node.name is a string', () => { + expect(testSubject(node)).to.equal(node.name) + }) + + it('should return null if node.name is not a string', () => { + expect(testSubject({ ...node, name: { id: node.name } })).to.be.null + }) + }) + + describe('node.tagName', () => { + let node: hast.Element + + beforeAll(() => { + node = { + children: [], + properties: {}, + tagName: 'div', + type: 'element' + } + }) + + it('should return node.tagName if node.tagName is a string', () => { + expect(testSubject(node)).to.equal(node.tagName) + }) + + it('should return null if node.tagName is not a string', () => { + expect(testSubject({ ...node, tagName: { id: node.tagName } })).to.be.null + }) + }) +}) diff --git a/src/utils/__tests__/parentlike.spec.ts b/src/utils/__tests__/parentlike.spec.ts new file mode 100644 index 0000000..c2ff06a --- /dev/null +++ b/src/utils/__tests__/parentlike.spec.ts @@ -0,0 +1,27 @@ +/** + * @file Unit Tests - parentlike + * @module unist-util-visit/utils/tests/unit/parentlike + */ + +import type { Type } from '@flex-development/unist-util-types' +import testSubject from '../parentlike' + +describe('unit:utils/parentlike', () => { + let type: Type + + beforeAll(() => { + type = 'root' + }) + + it('should return false if value is not nodelike', () => { + expect(testSubject('root')).to.be.false + }) + + it('should return false if value.children is invalid', () => { + expect(testSubject({ children: new Set(), type })).to.be.false + }) + + it('should return true if value is shaped like a parent', () => { + expect(testSubject({ children: [], type })).to.be.true + }) +}) diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..8bb4991 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,8 @@ +/** + * @file Entry Point - Utilities + * @module unist-util-visit/utils + */ + +export { default as nodelike } from './nodelike' +export { default as nodename } from './nodename' +export { default as parentlike } from './parentlike' diff --git a/src/utils/nodelike.ts b/src/utils/nodelike.ts new file mode 100644 index 0000000..db391f1 --- /dev/null +++ b/src/utils/nodelike.ts @@ -0,0 +1,24 @@ +/** + * @file Utilities - nodelike + * @module unist-util-visit/nodelike + */ + +import { isObjectCurly, isString } from '@flex-development/tutils' +import type { Node } from 'unist' + +/** + * Check if something looks like a {@linkcode Node}. + * + * @internal + * + * @this {void} + * + * @param {unknown} value - Thing to check + * @return {value is Node} `true` if `value` looks like a node + */ +function nodelike(this: void, value: unknown): value is Node { + if (!isObjectCurly(value)) return false + return 'type' in value && isString(value.type) && !!value.type.length +} + +export default nodelike diff --git a/src/utils/nodename.ts b/src/utils/nodename.ts new file mode 100644 index 0000000..2b7a371 --- /dev/null +++ b/src/utils/nodename.ts @@ -0,0 +1,37 @@ +/** + * @file Utilities - nodename + * @module unist-util-visit/nodename + */ + +import { isString, type Nullable } from '@flex-development/tutils' +import type { Node } from 'unist' + +/** + * Get a display name for `node`. + * + * The following properties will be used as display names if found: + * + * - `tagName` + * - `name` + * + * @internal + * + * @template {Node} [T=Node] - Node to check + * + * @this {void} + * + * @param {T} node - Node to check + * @return {Nullable} Display name or `null` + */ +function nodename( + this: void, + node: T +): Nullable { + return 'tagName' in node && isString(node.tagName) // hast + ? node.tagName + : 'name' in node && isString(node.name) // xast + ? node.name + : null +} + +export default nodename diff --git a/src/utils/parentlike.ts b/src/utils/parentlike.ts new file mode 100644 index 0000000..006e86a --- /dev/null +++ b/src/utils/parentlike.ts @@ -0,0 +1,24 @@ +/** + * @file Utilities - parentlike + * @module unist-util-visit/parentlike + */ + +import { isArray } from '@flex-development/tutils' +import type { Parent } from 'unist' +import nodelike from './nodelike' + +/** + * Check if something looks like a {@linkcode Parent}. + * + * @internal + * + * @this {void} + * + * @param {unknown} value - Thing to check + * @return {value is Parent} `true` if `value` looks like a parent + */ +function parentlike(this: void, value: unknown): value is Parent { + return nodelike(value) && 'children' in value && isArray(value.children) +} + +export default parentlike diff --git a/yarn.lock b/yarn.lock index 8a235a0..659fa84 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1827,11 +1827,13 @@ __metadata: "@html-eslint/parser": "npm:0.24.0" "@types/chai": "npm:4.3.12" "@types/eslint": "npm:8.56.5" + "@types/hast": "npm:3.0.4" "@types/is-ci": "npm:3.0.4" "@types/mdast": "npm:4.0.3" "@types/node": "npm:20.11.28" "@types/node-notifier": "npm:8.0.5" "@types/unist": "npm:3.0.2" + "@types/xast": "npm:2.0.4" "@typescript-eslint/eslint-plugin": "npm:7.2.0" "@typescript-eslint/parser": "npm:7.2.0" "@vates/toggle-scripts": "npm:1.0.0" @@ -2396,7 +2398,7 @@ __metadata: languageName: node linkType: hard -"@types/hast@npm:^3.0.0": +"@types/hast@npm:3.0.4": version: 3.0.4 resolution: "@types/hast@npm:3.0.4" dependencies: @@ -2536,6 +2538,15 @@ __metadata: languageName: node linkType: hard +"@types/xast@npm:2.0.4": + version: 2.0.4 + resolution: "@types/xast@npm:2.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10/41ed740a3deaa8c6aedf3d175ae2291d0bfaa5d56b0fa9d237e972e442364920e21dd63b4a3bfd078027752e681d643145c3e70c1aa02d96ddb20a9a4fc547dc + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:7.2.0": version: 7.2.0 resolution: "@typescript-eslint/eslint-plugin@npm:7.2.0"