0.4.15 • Published 5 months ago

@httpx/treeu v0.4.15

Weekly downloads
-
License
MIT
Repository
github
Last release
5 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  v3.0.3 /home/sebastien/github/httpx/packages/treeu


 āœ“ bench/search.bench.ts > Bench search (10_000 entries) 3827ms
     name                                                       hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · DfsTreeSearch.findOne(id_0) over 10_000          4,951,722.70  0.0002  0.2812  0.0002  0.0002  0.0004  0.0005  0.0009  ±0.36%  2475862   fastest
   · DfsTreeSearch.findOne(id_1000) over 10_000          36,877.99  0.0242  0.2565  0.0271  0.0265  0.0417  0.0496  0.1387  ±0.39%    18439
   · DfsTreeSearch.findOne(id_5000) over 10_000           7,109.04  0.1321  0.4006  0.1407  0.1401  0.2237  0.2336  0.3525  ±0.35%     3555
   · DfsTreeSearch.findOne(id_NotExists) over 10_000      3,637.79  0.2513  0.5789  0.2749  0.2768  0.3892  0.4068  0.5149  ±0.43%     1819   slowest

 āœ“ bench/mapper.bench.ts > Bench mapper (10_000 entries) 647ms
     name                                     hz     min      max    mean     p75      p99     p995     p999     rme  samples
   · FlatTreeWsMapper.toTreeNodesOrThrow  148.37  6.3635  11.2594  6.7397  6.8240  11.2594  11.2594  11.2594  ±2.05%       75

 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)
    134.27x faster than DfsTreeSearch.findOne(id_1000) over 10_000
    696.54x faster than DfsTreeSearch.findOne(id_5000) over 10_000
    1361.19x 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~ 270B
import { FlatTreeWsMapper } from '@httpx/treeu~ 802B

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)
Browserslistāœ…> 95% on 01/2025. defaults, chrome >= 96, firefox >= 105, edge >= 113, safari >= 15, ios >= 15, opera >= 103, not dead
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.10

9 months ago

0.4.9

9 months ago

0.4.8

10 months ago

0.4.15

5 months ago

0.4.13

5 months ago

0.4.14

5 months ago

0.4.11

9 months ago

0.4.12

9 months ago

0.4.7

11 months ago

0.4.6

1 year ago

0.4.5

1 year ago

0.4.4

1 year ago

0.4.3

1 year ago

0.4.2

1 year ago

0.4.1

1 year ago

0.4.0

1 year ago

0.3.0

1 year ago

0.2.0

1 year ago

0.1.0

1 year ago

0.0.2

1 year ago