Skip to content

Commit 4d00c47

Browse files
committed
chore: commit remaining changes
1 parent bac8c54 commit 4d00c47

53 files changed

Lines changed: 1002 additions & 4420 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.cjs

Lines changed: 0 additions & 8 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,14 @@ jobs:
1818
fetch-depth: 0
1919
token: ${{ secrets.TREE_STRUCTURE_TS_PAT }}
2020

21-
- uses: pnpm/action-setup@v2
21+
- uses: oven-sh/setup-bun@v2
2222
with:
23-
version: 7
23+
bun-version: "1.3.8"
2424

25-
- uses: actions/setup-node@v3
26-
with:
27-
node-version: "16"
28-
registry-url: "https://registry.npmjs.org"
29-
cache: "pnpm"
30-
31-
- run: pnpm install
25+
- run: bun install --frozen-lockfile
3226

3327
- name: Build
34-
run: pnpm run build
28+
run: bun run build
3529

3630
- name: Generate new tag version
3731
uses: mathieudutour/github-tag-action@v6.1

.github/workflows/release.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,29 @@ jobs:
1414
with:
1515
fetch-depth: 0
1616

17-
- uses: pnpm/action-setup@v2
17+
- uses: oven-sh/setup-bun@v2
1818
with:
19-
version: 7
19+
bun-version: "1.3.8"
2020

2121
- uses: actions/setup-node@v3
2222
with:
2323
node-version: "16"
2424
registry-url: "https://registry.npmjs.org"
25-
cache: "pnpm"
2625

27-
- run: pnpm install
26+
- run: bun install --frozen-lockfile
2827

2928
- name: Build
30-
run: pnpm run build
29+
run: bun run build
3130

3231
- name: Bump version
3332
run: |
3433
git config --global user.email "jdamaschke@visorian.com"
3534
git config --global user.name "Jan-Henrik Damaschke"
36-
pnpm dlx changelogithub
35+
bunx changelogithub
3736
env:
3837
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
3938

4039
- name: Publish package
41-
run: pnpm publish --no-git-checks
40+
run: bun publish
4241
env:
4342
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/test-build.yml

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,16 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v3
1313

14-
- name: Setup pnpm
15-
uses: pnpm/action-setup@v2
14+
- name: Setup Bun
15+
uses: oven-sh/setup-bun@v2
1616
with:
17-
version: 7
17+
bun-version: "1.3.8"
1818

19-
- name: Set node version to 16
20-
uses: actions/setup-node@v3
21-
with:
22-
node-version: 16
23-
cache: pnpm
24-
25-
- run: pnpm install
19+
- run: bun install --frozen-lockfile
2620

2721
- name: Run typecheck
28-
run: pnpm run typecheck
22+
run: bun run typecheck
2923

3024
- name: Run tests
31-
run: pnpm run test
32-
25+
run: bun run test
26+

.oxlintrc.json

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"ignorePatterns": [
4+
"dist/**"
5+
],
6+
"rules": {
7+
"typescript/await-thenable": "error",
8+
"typescript/consistent-return": "error",
9+
"typescript/consistent-type-exports": "error",
10+
"typescript/dot-notation": "error",
11+
"typescript/no-array-delete": "error",
12+
"typescript/no-base-to-string": "error",
13+
"typescript/no-confusing-void-expression": "error",
14+
"typescript/no-deprecated": "error",
15+
"typescript/no-duplicate-type-constituents": "error",
16+
"typescript/no-floating-promises": "error",
17+
"typescript/no-for-in-array": "error",
18+
"typescript/no-implied-eval": "error",
19+
"typescript/no-meaningless-void-operator": "error",
20+
"typescript/no-misused-promises": "error",
21+
"typescript/no-misused-spread": "error",
22+
"typescript/no-mixed-enums": "error",
23+
"typescript/no-redundant-type-constituents": "error",
24+
"typescript/no-unnecessary-boolean-literal-compare": "error",
25+
"typescript/no-unnecessary-condition": "error",
26+
"typescript/no-unnecessary-qualifier": "error",
27+
"typescript/no-unnecessary-template-expression": "error",
28+
"typescript/no-unnecessary-type-arguments": "error",
29+
"typescript/no-unnecessary-type-assertion": "error",
30+
"typescript/no-unnecessary-type-conversion": "error",
31+
"typescript/no-unnecessary-type-parameters": "error",
32+
"typescript/no-unsafe-argument": "error",
33+
"typescript/no-unsafe-assignment": "error",
34+
"typescript/no-unsafe-call": "error",
35+
"typescript/no-unsafe-enum-comparison": "error",
36+
"typescript/no-unsafe-member-access": "error",
37+
"typescript/no-unsafe-return": "error",
38+
"typescript/no-unsafe-type-assertion": "error",
39+
"typescript/no-unsafe-unary-minus": "error",
40+
"typescript/no-useless-default-assignment": "error",
41+
"typescript/non-nullable-type-assertion-style": "error",
42+
"typescript/only-throw-error": "error",
43+
"typescript/prefer-find": "error",
44+
"typescript/prefer-includes": "error",
45+
"typescript/prefer-nullish-coalescing": "error",
46+
"typescript/prefer-optional-chain": "error",
47+
"typescript/prefer-promise-reject-errors": "error",
48+
"typescript/prefer-readonly-parameter-types": "error",
49+
"typescript/prefer-readonly": "error",
50+
"typescript/prefer-reduce-type-parameter": "error",
51+
"typescript/prefer-regexp-exec": "error",
52+
"typescript/prefer-return-this-type": "error",
53+
"typescript/prefer-string-starts-ends-with": "error",
54+
"typescript/promise-function-async": "error",
55+
"typescript/related-getter-setter-pairs": "error",
56+
"typescript/require-array-sort-compare": "error",
57+
"typescript/require-await": "error",
58+
"typescript/restrict-plus-operands": "error",
59+
"typescript/restrict-template-expressions": "error",
60+
"typescript/return-await": "error",
61+
"typescript/strict-boolean-expressions": "error",
62+
"typescript/strict-void-return": "error",
63+
"typescript/switch-exhaustiveness-check": "error",
64+
"typescript/unbound-method": "error",
65+
"typescript/use-unknown-in-catch-callback-variable": "error"
66+
}
67+
}

.vscode/settings.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22
"vitest.enable": true,
33
"prettier.enable": false,
44
"editor.formatOnSave": false,
5-
"editor.codeActionsOnSave": {
6-
"source.fixAll.eslint": true
7-
},
85
"typescript.format.semicolons": "remove",
96
"typescript.format.enable": true,
107
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false,
118
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
129
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true,
13-
"typescript.preferences.quoteStyle": "single",
14-
}
10+
"typescript.preferences.quoteStyle": "single"
11+
}

benchmark/helpers.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Tree } from "../src/Tree";
2+
import { TreeNode } from "../src/TreeNode";
3+
4+
export type Traversal = "breadthFirst" | "depthFirst" | "preOrder" | "postOrder";
5+
6+
export type DeepTreeFixture = {
7+
tree: Tree<number>;
8+
deepest: TreeNode<number>;
9+
};
10+
11+
export const readPositiveInt = (name: string, fallback: number): number => {
12+
const raw = process.env[name];
13+
if (raw === undefined) return fallback;
14+
15+
const parsed = Number.parseInt(raw, 10);
16+
if (!Number.isFinite(parsed) || parsed <= 0) {
17+
throw new Error(`${name} must be a positive integer`);
18+
}
19+
20+
return parsed;
21+
};
22+
23+
export const assert = (condition: boolean, message: string): void => {
24+
if (!condition) {
25+
throw new Error(message);
26+
}
27+
};
28+
29+
export const buildDeepTree = (depth: number): DeepTreeFixture => {
30+
const tree = new Tree(0);
31+
let current = tree.root!;
32+
33+
for (let value = 1; value <= depth; value += 1) {
34+
current = current.addChild(value);
35+
}
36+
37+
return { tree, deepest: current };
38+
};
39+
40+
export const expectedWideNodeCount = (branching: number, levels: number): number => {
41+
let total = 0;
42+
let levelWidth = 1;
43+
44+
for (let level = 0; level <= levels; level += 1) {
45+
total += levelWidth;
46+
levelWidth *= branching;
47+
}
48+
49+
return total;
50+
};
51+
52+
export const buildWideTree = (branching: number, levels: number): Tree<number> => {
53+
const tree = new Tree(0);
54+
let currentLevel = [tree.root!];
55+
let value = 1;
56+
57+
for (let level = 0; level < levels; level += 1) {
58+
const nextLevel: TreeNode<number>[] = [];
59+
60+
for (const node of currentLevel) {
61+
for (let index = 0; index < branching; index += 1) {
62+
nextLevel.push(node.addChild(value));
63+
value += 1;
64+
}
65+
}
66+
67+
currentLevel = nextLevel;
68+
}
69+
70+
return tree;
71+
};
72+
73+
export const countTraversal = (tree: Tree<number>, mode: Traversal): number => {
74+
let visited = 0;
75+
tree.traverse(() => {
76+
visited += 1;
77+
}, mode);
78+
return visited;
79+
};

benchmark/huge-tree.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Tree } from "../src/Tree";
2+
import { TreeNode } from "../src/TreeNode";
3+
import {
4+
assert,
5+
buildDeepTree,
6+
buildWideTree,
7+
countTraversal,
8+
expectedWideNodeCount,
9+
readPositiveInt,
10+
} from "./helpers";
11+
12+
const DEEP_DEPTH = readPositiveInt("DEEP_DEPTH", 250_000);
13+
const WIDE_BRANCHING = readPositiveInt("WIDE_BRANCHING", 12);
14+
const WIDE_LEVELS = readPositiveInt("WIDE_LEVELS", 5);
15+
16+
const formatMs = (durationMs: number): string => durationMs.toFixed(2).padStart(10);
17+
18+
const benchmark = <T>(name: string, fn: () => T): T => {
19+
const start = performance.now();
20+
const result = fn();
21+
const end = performance.now();
22+
const durationMs = end - start;
23+
console.log(`${name.padEnd(36)} ${formatMs(durationMs)} ms`);
24+
return result;
25+
};
26+
27+
console.log("Huge Tree Benchmark");
28+
console.log(`DEEP_DEPTH=${DEEP_DEPTH}`);
29+
console.log(`WIDE_BRANCHING=${WIDE_BRANCHING}`);
30+
console.log(`WIDE_LEVELS=${WIDE_LEVELS}`);
31+
console.log("");
32+
33+
let deepTree: Tree<number>;
34+
let deepLeaf: TreeNode<number>;
35+
36+
benchmark("build deep tree", () => {
37+
const built = buildDeepTree(DEEP_DEPTH);
38+
deepTree = built.tree;
39+
deepLeaf = built.deepest;
40+
});
41+
42+
const deepNodeCount = DEEP_DEPTH + 1;
43+
44+
const deepPath = benchmark("deep getPath", () => deepLeaf!.getPath());
45+
assert(deepPath.length === deepNodeCount, "deep getPath length mismatch");
46+
47+
const deepAll = benchmark("deep all", () => deepTree!.all());
48+
assert(deepAll.length === DEEP_DEPTH, "deep all length mismatch");
49+
50+
const deepBreadthFirstCount = benchmark("deep traverse breadthFirst", () => countTraversal(deepTree!, "breadthFirst"));
51+
assert(deepBreadthFirstCount === deepNodeCount, "deep breadthFirst count mismatch");
52+
53+
const deepDepthFirstCount = benchmark("deep traverse depthFirst", () => countTraversal(deepTree!, "depthFirst"));
54+
assert(deepDepthFirstCount === deepNodeCount, "deep depthFirst count mismatch");
55+
56+
const deepPreOrderCount = benchmark("deep traverse preOrder", () => countTraversal(deepTree!, "preOrder"));
57+
assert(deepPreOrderCount === deepNodeCount, "deep preOrder count mismatch");
58+
59+
const deepPostOrderCount = benchmark("deep traverse postOrder", () => countTraversal(deepTree!, "postOrder"));
60+
assert(deepPostOrderCount === deepNodeCount, "deep postOrder count mismatch");
61+
62+
let wideTree: Tree<number>;
63+
64+
benchmark("build wide tree", () => {
65+
wideTree = buildWideTree(WIDE_BRANCHING, WIDE_LEVELS);
66+
});
67+
68+
const expectedWideNodes = expectedWideNodeCount(WIDE_BRANCHING, WIDE_LEVELS);
69+
70+
console.log(`deepNodeCount=${deepNodeCount}`);
71+
console.log(`wideNodeCount=${expectedWideNodes}`);
72+
console.log("");
73+
74+
const wideAll = benchmark("wide all", () => wideTree!.all());
75+
assert(wideAll.length === expectedWideNodes - 1, "wide all length mismatch");
76+
77+
const wideBreadthFirstCount = benchmark("wide traverse breadthFirst", () => countTraversal(wideTree!, "breadthFirst"));
78+
assert(wideBreadthFirstCount === expectedWideNodes, "wide breadthFirst count mismatch");
79+
80+
const widePostOrderCount = benchmark("wide traverse postOrder", () => countTraversal(wideTree!, "postOrder"));
81+
assert(widePostOrderCount === expectedWideNodes, "wide postOrder count mismatch");
82+
83+
console.log("\nBenchmark completed successfully.");

0 commit comments

Comments
 (0)