0.4.6 • Published 8 months ago

@httpx/treeu v0.4.6

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

@httpx/treeu

Fast and lightweight (~300B) utilities to work with trees.

npm changelog codecov bundles node browserslist size downloads license

Install

$ npm install @httpx/treeu
$ yarn add @httpx/treeu
$ pnpm add @httpx/treeu

Features

Documentation

šŸ‘‰ Official website or Github Readme

Usage

Search

DFSTreeSearch

Depth-First Search (DFS) algorithm for tree structures. It uses a stack rather than recursion in order to support deeply nested trees without call-stack overflows. It is well suited for exploring a branch of a data structure in depth and usually preferred when memory usage is a concern or when the data structure has many nodes with few levels.

import { Tree, type TreeNode } from '@httpx/treeu';

type CustomValue =
    | { type: 'folder'; size?: never }
    | { type: 'file'; size: number };

const treeNodes: TreeNode<CustomValue>[] = [
    {
        id: 'file2.ts',
        parentId: null,
        value: { size: 10, type: 'file' },
        children: [],
    },
    {
        id: 'folder1',
        parentId: null,
        value: { type: 'folder' },
        children: [
            {
                id: 'folder1/file1.ts',
                parentId: 'folder1',
                value: { size: 30, type: 'file' },
                children: [],
            },
        ],
    },
];

const search = new DfsTreeSearch<CustomValue>(treeNodes);
const res1 = search.findOne('folder1/file1.ts');
const res2 = search.findOne(['id', '===', 'folder1/file1.ts']);
const res3 = search.findOne((treeNode) => treeNode.value.size === 30);
const res4 = search.findOne(['parentId', '===', 'folder1']);

// res1 === res2 === res3 === res4

Mapper

FlatTreeWsMapper

FlatTreeWsMapperDescription
toTreeNodesConvert to flat map with separator
fromTreeNodesConvert a tree to a flat map with separator
import { FlatTreeWsMapper, type FlatTreeWs } from '@httpx/treeu';

type CustomValue =
    | { type: 'folder'; size?: never }
    | { type: 'file'; size: number };

// Use an object or a Record<string, CustomValue>
const paths: FlatTreeWs<CustomValue> = new Map([
    [ 'file1.ts', { type: 'file', size: 10 } ],
    [ 'folder1', { type: 'folder' }],
    [ 'folder1/file1.ts', { type: 'file', size: 30 }],
]);

const mapper = new FlatTreeWsMapper<CustomValue>();

const treeResult = mapper.toTreeNodes(paths, {
    separator: '/',
});

// Will return 
const expected: TreeNode<CustomValue>[] = [
    {
        id: 'file1.ts',
        parentId: null,
        value: {
            size: 10,
            type: 'file',
        },
        children: [],
    },
    {
        id: 'folder1',
        parentId: null,
        value: {
            type: 'folder',
        },
        children: [
            {
                id: 'folder1/file1.ts',
                parentId: 'folder1',
                value: {
                    size: 30,
                    type: 'file',
                },
                children: [],
            },
        ],
    },
];

TreeNode

Example

Example of TreeNode[] typing:

import { Tree, TreeNode } from '@httpx/treeu';

type CustomValue =
    | { type: 'folder'; size?: never }
    | { type: 'file'; size: number };

const treeNodes: TreeNode<CustomValue>[] = [
    {
        id: 'file1.ts',
        parentId: null,
        value: {
            size: 10,
            type: 'file',
        },
        children: [],
    },
    {
        id: 'file2.ts',
        parentId: null,
        value: {
            size: 20,
            type: 'file',
        },
        children: [],
    },
    {
        id: 'folder1',
        parentId: null,
        value: {
            type: 'folder',
        },
        children: [
            {
                id: 'folder1/file1.ts',
                parentId: 'folder1',
                value: {
                    size: 30,
                    type: 'file',
                },
                children: [],
            },
        ],
    },
    {
        id: 'folder2',
        parentId: null,
        value: {
            type: 'folder',
        },
        children: [
            {
                id: 'folder2/file1.ts',
                parentId: 'folder2',
                value: {
                    size: 40,
                    type: 'file',
                },
                children: [],
            },
            {
                id: 'folder2/subfolder1',
                parentId: 'folder2',
                value: {
                    type: 'folder',
                },
                children: [
                    {
                        id: 'folder2/subfolder1/file1.ts',
                        parentId: 'folder2/subfolder1',
                        value: {
                            size: 50,
                            type: 'file',
                        },
                        children: [],
                    },
                ],
            },
        ],
    },
    {
        id: 'folder3',
        parentId: null,
        value: {
            type: 'folder',
        },
        children: [],
    },
];

Tree

Types

TreeNode<TValue, TId>TypeDescription
idTValue extends string\|numberUnique identifier of the node.
parentIdTValue extends string\|numberReference to the parent node
childrenTreeNode<TValue, TId>[]Children nodes
valueTValue\|undefinedCustom value associated with the node

Benchmarks

Performance is continuously monitored thanks to codspeed.io.

CodSpeed Badge

 RUN  v2.0.5 

 āœ“ bench/search.bench.ts (4) 6714ms
   āœ“ Bench search (10_000 entries) (4) 6713ms
     name                                                       hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · DfsTreeSearch.findOne(id_0) over 10_000          9,360,159.92  0.0001  3.5234  0.0001  0.0001  0.0002  0.0002  0.0004  ±1.88%  4680081   fastest
   · DfsTreeSearch.findOne(id_1000) over 10_000          64,337.37  0.0097  0.7432  0.0155  0.0151  0.0437  0.0752  0.2380  ±1.09%    32169
   · DfsTreeSearch.findOne(id_5000) over 10_000          13,027.78  0.0505  0.9968  0.0768  0.0753  0.2389  0.2790  0.4839  ±1.33%     6514
   · DfsTreeSearch.findOne(id_NotExists) over 10_000      6,335.21  0.1020  0.8740  0.1578  0.1582  0.4216  0.4970  0.6655  ±1.47%     3168   slowest
 āœ“ bench/mapper.bench.ts (1) 621ms
   āœ“ Bench mapper (10_000 entries) (1) 620ms
     name                                     hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · FlatTreeWsMapper.toTreeNodesOrThrow  323.01  2.1707  9.7894  3.0959  3.5083  9.2491  9.7894  9.7894  ±5.95%      162


 BENCH  Summary

  FlatTreeWsMapper.toTreeNodesOrThrow - bench/mapper.bench.ts > Bench mapper (10_000 entries)

  DfsTreeSearch.findOne(id_0) over 10_000 - bench/search.bench.ts > Bench search (10_000 entries)
    145.49x faster than DfsTreeSearch.findOne(id_1000) over 10_000
    718.48x faster than DfsTreeSearch.findOne(id_5000) over 10_000
    1477.48x faster than DfsTreeSearch.findOne(id_NotExists) over 10_000
 

See benchmark file for details.

Bundle size

Bundle size is tracked by a size-limit configuration

Scenario (esm)Size (compressed)
import { DfsTreeSearch } from '@httpx/treeu~ 350B
import { FlatTreeWsMapper } from '@httpx/treeu~ 800B

For CJS usage (not recommended) track the size on bundlephobia.

Compatibility

LevelCIDescription
Nodeāœ…CI for 18.x, 20.x & 22.x.
Browserāœ…Tested with latest chrome (vitest/playwright)
Browsersāœ…> 96% on 07/2024. Mins to Chrome 96+, Firefox 90+, Edge 19+, iOS 12+, Safari 12+, Opera 77+
Edgeāœ…Ensured on CI with @vercel/edge-runtime.
Cloudflareāœ…Ensured with @cloudflare/vitest-pool-workers (see wrangler.toml
Edgeāœ…Ensured on CI with @vercel/edge-runtime.
Typescriptāœ…TS 5.0 + / are-the-type-wrong checks on CI.
ES2022āœ…Dist files checked with es-check
Performanceāœ…Monitored with codspeed.io

For older browsers: most frontend frameworks can transpile the library (ie: nextjs...)

Contributors

Contributions are welcome. Have a look to the CONTRIBUTING document.

Sponsors

If my OSS work brightens your day, let's take it to new heights together! Sponsor, coffee, or star – any gesture of support fuels my passion to improve. Thanks for being awesome! šŸ™ā¤ļø

Special thanks to

License

MIT Ā© belgattitude and contributors.

0.4.6

8 months ago

0.4.5

8 months ago

0.4.4

8 months ago

0.4.3

8 months ago

0.4.2

9 months ago

0.4.1

9 months ago

0.4.0

10 months ago

0.3.0

10 months ago

0.2.0

10 months ago

0.1.0

10 months ago

0.0.2

10 months ago