data-structure-typed 1.41.3 → 1.41.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +561 -265
  3. package/benchmark/report.html +79 -0
  4. package/benchmark/report.json +343 -28
  5. package/dist/cjs/data-structures/binary-tree/binary-tree.js +11 -10
  6. package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
  7. package/dist/mjs/data-structures/binary-tree/binary-tree.js +11 -10
  8. package/dist/umd/data-structure-typed.min.js +1 -1
  9. package/dist/umd/data-structure-typed.min.js.map +1 -1
  10. package/package.json +8 -4
  11. package/src/data-structures/binary-tree/binary-tree.ts +12 -9
  12. package/test/config.ts +1 -1
  13. package/test/performance/data-structures/binary-tree/avl-tree.test.ts +36 -0
  14. package/test/performance/data-structures/binary-tree/binary-tree.test.ts +45 -0
  15. package/test/performance/data-structures/binary-tree/bst.test.ts +36 -0
  16. package/test/performance/data-structures/graph/directed-graph.test.ts +49 -0
  17. package/test/performance/data-structures/heap/heap.test.ts +30 -0
  18. package/test/performance/data-structures/linked-list/doubly-linked-list.test.ts +40 -0
  19. package/test/performance/data-structures/linked-list/singly-linked-list.test.ts +34 -0
  20. package/test/performance/data-structures/priority-queue/max-priority-queue.test.ts +19 -0
  21. package/test/performance/data-structures/queue/deque.test.ts +8 -6
  22. package/test/performance/data-structures/queue/queue.test.ts +17 -12
  23. package/test/performance/data-structures/trie/trie.test.ts +22 -0
  24. package/test/performance/reportor.ts +183 -0
  25. package/test/performance/types/index.ts +1 -0
  26. package/test/performance/types/reportor.ts +3 -0
  27. package/test/types/utils/index.ts +1 -0
  28. package/test/types/utils/json2html.ts +1 -0
  29. package/test/unit/data-structures/binary-tree/rb-tree.test.ts +1 -1
  30. package/test/unit/data-structures/heap/heap.test.ts +5 -4
  31. package/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +0 -23
  32. package/test/unit/data-structures/linked-list/linked-list.test.ts +3 -30
  33. package/test/unit/data-structures/linked-list/singly-linked-list.test.ts +0 -21
  34. package/test/unit/data-structures/matrix/matrix2d.test.ts +1 -1
  35. package/test/unit/data-structures/priority-queue/max-priority-queue.test.ts +0 -32
  36. package/test/unit/data-structures/queue/queue.test.ts +3 -39
  37. package/test/utils/array.ts +5514 -0
  38. package/test/utils/big-o.ts +14 -8
  39. package/test/utils/console.ts +31 -0
  40. package/test/utils/index.ts +5 -0
  41. package/test/utils/is.ts +56 -0
  42. package/test/utils/json2html.ts +322 -0
  43. package/test/utils/number.ts +10 -0
  44. package/test/utils/string.ts +1 -0
  45. package/test/config.js +0 -4
  46. package/test/performance/index.ts +0 -47
  47. package/test/types/index.js +0 -29
  48. package/test/types/utils/big-o.js +0 -2
  49. package/test/types/utils/index.js +0 -29
  50. package/test/utils/big-o.js +0 -222
  51. package/test/utils/index.js +0 -30
  52. package/test/utils/number.js +0 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "data-structure-typed",
3
- "version": "1.41.3",
3
+ "version": "1.41.5",
4
4
  "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/mjs/index.js",
@@ -31,9 +31,9 @@
31
31
  "reformat": "npm run reformat:src && npm run reformat:test",
32
32
  "update:subs": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev",
33
33
  "install:all-subs": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev",
34
- "test": "jest",
34
+ "test": "jest --runInBand",
35
35
  "test:integration": "npm run update:subs && jest --config jest.integration.config.js",
36
- "benchmark": "ts-node test/performance/index.ts",
36
+ "benchmark": "ts-node test/performance/reportor.ts",
37
37
  "check:deps": "dependency-cruiser src",
38
38
  "changelog": "auto-changelog",
39
39
  "coverage:badge": "istanbul-badges-readme",
@@ -41,7 +41,7 @@
41
41
  "copy:to-subs": "sh scripts/copy_to_all_subs.sh",
42
42
  "publish:subs": "npm run copy:to-subs && sh scripts/publish_all_subs.sh",
43
43
  "publish:docs": "sh scripts/publish_docs.sh",
44
- "publish:all": "npm run ci && npm publish && npm run publish:docs && npm run publish:subs"
44
+ "publish:all": "npm run ci && npm run benchmark && npm publish && npm run publish:docs && npm run publish:subs"
45
45
  },
46
46
  "repository": {
47
47
  "type": "git",
@@ -60,6 +60,7 @@
60
60
  "@types/benchmark": "^2.1.3",
61
61
  "@types/jest": "^29.5.5",
62
62
  "@types/node": "^20.8.2",
63
+ "@types/underscore": "^1.11.12",
63
64
  "@typescript-eslint/eslint-plugin": "^6.7.4",
64
65
  "@typescript-eslint/parser": "^6.7.4",
65
66
  "auto-changelog": "^2.4.0",
@@ -132,9 +133,12 @@
132
133
  "UMD",
133
134
  "esmodule",
134
135
  "java.util",
136
+ "c++ stl",
135
137
  "c++ std",
136
138
  "Python collections",
137
139
  "System.Collections.Generic",
140
+ "STL",
141
+ "stl",
138
142
  "STD",
139
143
  "std",
140
144
  "util",
@@ -179,7 +179,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
179
179
  while (queue.size > 0) {
180
180
  const cur = queue.shift();
181
181
  if (cur) {
182
- if (newNode && cur.key === newNode.key) return;
182
+ if (newNode && cur.key === newNode.key) {
183
+ cur.value = newNode.value;
184
+ return;
185
+ }
183
186
  const inserted = this._addTo(newNode, cur);
184
187
  if (inserted !== undefined) return inserted;
185
188
  if (cur.left) queue.push(cur.left);
@@ -201,16 +204,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
201
204
  return;
202
205
  }
203
206
 
204
- const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
205
- const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
207
+ // const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
208
+ // const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
206
209
 
207
210
  if (this.root) {
208
- if (existNode) {
209
- existNode.value = value;
210
- inserted = existNode;
211
- } else {
212
- inserted = _bfs(this.root, needInsert);
213
- }
211
+ // if (existNode) {
212
+ // existNode.value = value;
213
+ // inserted = existNode;
214
+ // } else {
215
+ inserted = _bfs(this.root, needInsert);
216
+ // }
214
217
  } else {
215
218
  this._setRoot(needInsert);
216
219
  if (needInsert !== null) {
package/test/config.ts CHANGED
@@ -1 +1 @@
1
- export const isDebugTest = true;
1
+ export const isDebugTest = false;
@@ -0,0 +1,36 @@
1
+ import {AVLTree} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {getRandomIntArray, magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const avl = new AVLTree<number>();
7
+ const {N_LOG_N} = magnitude;
8
+ const arr = getRandomIntArray(N_LOG_N, 0, N_LOG_N, true);
9
+
10
+ suite
11
+ .add(`${N_LOG_N} add randomly`, () => {
12
+ avl.clear();
13
+ for (let i = 0; i < arr.length; i++) {
14
+ avl.add(arr[i]);
15
+ }
16
+ })
17
+ .add(`${N_LOG_N} add & delete randomly`, () => {
18
+ avl.clear();
19
+ for (let i = 0; i < arr.length; i++) {
20
+ avl.add(arr[i]);
21
+ }
22
+ for (let i = 0; i < arr.length; i++) {
23
+ avl.delete(arr[i]);
24
+ }
25
+ })
26
+ .add(`${N_LOG_N} addMany`, () => {
27
+ avl.clear();
28
+ avl.addMany(arr);
29
+ })
30
+ .add(`${N_LOG_N} get`, () => {
31
+ for (let i = 0; i < arr.length; i++) {
32
+ avl.get(arr[i]);
33
+ }
34
+ });
35
+
36
+ export {suite};
@@ -0,0 +1,45 @@
1
+ import {BinaryTree} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {getRandomIntArray, magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const biTree = new BinaryTree<number>();
7
+ const {N_LOG_N} = magnitude;
8
+ const arr = getRandomIntArray(N_LOG_N, 0, N_LOG_N, true);
9
+
10
+ suite
11
+ .add(`${N_LOG_N} add randomly`, () => {
12
+ biTree.clear();
13
+ for (let i = 0; i < arr.length; i++) {
14
+ biTree.add(arr[i]);
15
+ }
16
+ })
17
+ .add(`${N_LOG_N} add & delete randomly`, () => {
18
+ biTree.clear();
19
+ for (let i = 0; i < arr.length; i++) {
20
+ biTree.add(arr[i]);
21
+ }
22
+ for (let i = 0; i < arr.length; i++) {
23
+ biTree.delete(arr[i]);
24
+ }
25
+ })
26
+ .add(`${N_LOG_N} addMany`, () => {
27
+ biTree.clear();
28
+ biTree.addMany(arr);
29
+ })
30
+ .add(`${N_LOG_N} get`, () => {
31
+ for (let i = 0; i < arr.length; i++) {
32
+ biTree.get(arr[i]);
33
+ }
34
+ })
35
+ .add(`${N_LOG_N} dfs`, () => {
36
+ for (let i = 0; i < N_LOG_N; i++) biTree.dfs();
37
+ })
38
+ .add(`${N_LOG_N} bfs`, () => {
39
+ for (let i = 0; i < N_LOG_N; i++) biTree.bfs();
40
+ })
41
+ .add(`${N_LOG_N} morris`, () => {
42
+ for (let i = 0; i < N_LOG_N; i++) biTree.morris(n => n, 'pre');
43
+ });
44
+
45
+ export {suite};
@@ -0,0 +1,36 @@
1
+ import {BST} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {getRandomIntArray, magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const bst = new BST<number>();
7
+ const {N_LOG_N} = magnitude;
8
+ const arr = getRandomIntArray(N_LOG_N, 0, N_LOG_N, true);
9
+
10
+ suite
11
+ .add(`${N_LOG_N} add randomly`, () => {
12
+ bst.clear();
13
+ for (let i = 0; i < arr.length; i++) {
14
+ bst.add(arr[i]);
15
+ }
16
+ })
17
+ .add(`${N_LOG_N} add & delete randomly`, () => {
18
+ bst.clear();
19
+ for (let i = 0; i < arr.length; i++) {
20
+ bst.add(arr[i]);
21
+ }
22
+ for (let i = 0; i < arr.length; i++) {
23
+ bst.delete(arr[i]);
24
+ }
25
+ })
26
+ .add(`${N_LOG_N} addMany`, () => {
27
+ bst.clear();
28
+ bst.addMany(arr);
29
+ })
30
+ .add(`${N_LOG_N} get`, () => {
31
+ for (let i = 0; i < arr.length; i++) {
32
+ bst.get(arr[i]);
33
+ }
34
+ });
35
+
36
+ export {suite};
@@ -0,0 +1,49 @@
1
+ import {DirectedGraph} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {getRandomIndex, getRandomWords, magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {THOUSAND} = magnitude;
7
+ const graph = new DirectedGraph<number, number>();
8
+ const vertexes = getRandomWords(THOUSAND);
9
+
10
+ suite
11
+ .add(`${THOUSAND} addVertex`, () => {
12
+ for (const v of vertexes) {
13
+ graph.addVertex(v);
14
+ }
15
+ })
16
+ .add(`${THOUSAND} addEdge`, () => {
17
+ for (let i = 0; i < THOUSAND; i++) {
18
+ const v1 = vertexes[getRandomIndex(vertexes)];
19
+ const v2 = vertexes[getRandomIndex(vertexes)];
20
+ graph.addEdge(v1, v2);
21
+ }
22
+ })
23
+ .add(`${THOUSAND} getVertex`, () => {
24
+ for (let i = 0; i < THOUSAND; i++) {
25
+ graph.getVertex(vertexes[getRandomIndex(vertexes)]);
26
+ }
27
+ })
28
+ .add(`${THOUSAND} getEdge`, () => {
29
+ for (let i = 0; i < THOUSAND; i++) {
30
+ graph.getEdge(vertexes[getRandomIndex(vertexes)], vertexes[getRandomIndex(vertexes)]);
31
+ }
32
+ })
33
+ .add(`tarjan`, () => {
34
+ // for (let i = 0; i < THOUSAND; i++) {
35
+ graph.tarjan(true);
36
+ // }
37
+ })
38
+ .add(`tarjan all`, () => {
39
+ // for (let i = 0; i < THOUSAND; i++) {
40
+ graph.tarjan(true, true, true, true);
41
+ // }
42
+ })
43
+ .add(`topologicalSort`, () => {
44
+ // for (let i = 0; i < THOUSAND; i++) {
45
+ graph.topologicalSort('key');
46
+ // }
47
+ });
48
+
49
+ export {suite};
@@ -0,0 +1,30 @@
1
+ import {FibonacciHeap, Heap} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {N_LOG_N} = magnitude;
7
+
8
+ suite
9
+ .add(`${N_LOG_N} add & pop`, () => {
10
+ const heap = new Heap<number>({comparator: (a, b) => b - a});
11
+
12
+ for (let i = 0; i < N_LOG_N; i++) {
13
+ heap.add(i);
14
+ }
15
+
16
+ for (let i = 0; i < N_LOG_N; i++) {
17
+ heap.pop();
18
+ }
19
+ })
20
+ .add(`${N_LOG_N} fib add & pop`, () => {
21
+ const fbHeap = new FibonacciHeap<number>();
22
+ for (let i = 1; i <= N_LOG_N; i++) {
23
+ fbHeap.push(i);
24
+ }
25
+ for (let i = 1; i <= N_LOG_N; i++) {
26
+ fbHeap.pop();
27
+ }
28
+ });
29
+
30
+ export {suite};
@@ -0,0 +1,40 @@
1
+ import {DoublyLinkedList, DoublyLinkedListNode} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {LINEAR, N_LOG_N} = magnitude;
7
+
8
+ suite
9
+ .add(`${LINEAR} unshift`, () => {
10
+ const list = new DoublyLinkedList<number>();
11
+
12
+ for (let i = 0; i < LINEAR; i++) {
13
+ list.unshift(i);
14
+ }
15
+ })
16
+ .add(`${LINEAR} unshift & shift`, () => {
17
+ const list = new DoublyLinkedList<number>();
18
+
19
+ for (let i = 0; i < LINEAR; i++) {
20
+ list.unshift(i);
21
+ }
22
+ for (let i = 0; i < LINEAR; i++) {
23
+ list.shift();
24
+ }
25
+ })
26
+ .add(`${N_LOG_N} insertBefore`, () => {
27
+ const doublyList = new DoublyLinkedList<number>();
28
+ let midNode: DoublyLinkedListNode | null = null;
29
+ const midIndex = Math.floor(N_LOG_N / 2);
30
+ for (let i = 0; i < N_LOG_N; i++) {
31
+ doublyList.push(i);
32
+ if (i === midIndex) {
33
+ midNode = doublyList.getNode(i);
34
+ } else if (i > midIndex && midNode) {
35
+ doublyList.insertBefore(midNode, i);
36
+ }
37
+ }
38
+ });
39
+
40
+ export {suite};
@@ -0,0 +1,34 @@
1
+ import {SinglyLinkedList, SinglyLinkedListNode} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {N_LOG_N} = magnitude;
7
+
8
+ suite
9
+ .add(`${N_LOG_N} push & pop`, () => {
10
+ const list = new SinglyLinkedList<number>();
11
+
12
+ for (let i = 0; i < N_LOG_N; i++) {
13
+ list.push(i);
14
+ }
15
+
16
+ for (let i = 0; i < N_LOG_N; i++) {
17
+ list.pop();
18
+ }
19
+ })
20
+ .add(`${N_LOG_N} insertBefore`, () => {
21
+ const singlyList = new SinglyLinkedList<number>();
22
+ let midSinglyNode: SinglyLinkedListNode | null = null;
23
+ const midIndex = Math.floor(N_LOG_N / 2);
24
+ for (let i = 0; i < N_LOG_N; i++) {
25
+ singlyList.push(i);
26
+ if (i === midIndex) {
27
+ midSinglyNode = singlyList.getNode(i);
28
+ } else if (i > midIndex && midSinglyNode) {
29
+ singlyList.insertBefore(midSinglyNode.value, i);
30
+ }
31
+ }
32
+ });
33
+
34
+ export {suite};
@@ -0,0 +1,19 @@
1
+ import {MaxPriorityQueue} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {TEN_THOUSAND} = magnitude;
7
+
8
+ suite.add(`${TEN_THOUSAND} refill & poll`, () => {
9
+ const nodes = Array.from(
10
+ new Set<number>(Array.from(new Array(TEN_THOUSAND), () => Math.floor(Math.random() * TEN_THOUSAND * 100)))
11
+ );
12
+ const maxPQ = new MaxPriorityQueue<number>();
13
+ maxPQ.refill(nodes);
14
+ while (maxPQ.size > 0) {
15
+ maxPQ.poll();
16
+ }
17
+ });
18
+
19
+ export {suite};
@@ -1,19 +1,21 @@
1
- import {Deque} from "../../../../src";
1
+ import {Deque} from '../../../../src';
2
2
  import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
3
4
 
4
5
  export const suite = new Benchmark.Suite();
6
+ const {LINEAR} = magnitude;
5
7
 
6
8
  suite
7
- .add('push', () => {
9
+ .add(`${LINEAR} push`, () => {
8
10
  const deque = new Deque<number>();
9
- for (let i = 0; i < 10; i++) {
11
+ for (let i = 0; i < LINEAR; i++) {
10
12
  deque.push(i);
11
13
  }
12
14
  })
13
- .add('shift', () => {
15
+ .add(`${LINEAR} shift`, () => {
14
16
  const deque = new Deque<number>();
15
- for (let i = 0; i < 10; i++) {
17
+ for (let i = 0; i < LINEAR; i++) {
16
18
  deque.push(i);
17
19
  deque.shift();
18
20
  }
19
- })
21
+ });
@@ -1,20 +1,25 @@
1
- import {Queue} from "../../../../src";
2
-
1
+ import {Queue} from '../../../../src';
3
2
  import * as Benchmark from 'benchmark';
3
+ import {magnitude} from '../../../utils';
4
4
 
5
- export const suite = new Benchmark.Suite();
5
+ const suite = new Benchmark.Suite();
6
+ const {LINEAR} = magnitude;
6
7
 
7
8
  suite
8
- .add('push', () => {
9
+ .add(`${LINEAR} push`, () => {
9
10
  const queue = new Queue<number>();
10
- for (let i = 0; i < 1000000; i++) {
11
+
12
+ for (let i = 0; i < LINEAR; i++) {
11
13
  queue.push(i);
12
14
  }
13
15
  })
14
- // .add('shift', () => {
15
- // const queue = new Queue<number>();
16
- // for (let i = 0; i < 10000; i++) {
17
- // queue.push(i);
18
- // queue.shift();
19
- // }
20
- // })
16
+ .add(`${LINEAR} push & shift`, () => {
17
+ const queue = new Queue<number>();
18
+
19
+ for (let i = 0; i < LINEAR; i++) {
20
+ queue.push(i);
21
+ queue.shift();
22
+ }
23
+ });
24
+
25
+ export {suite};
@@ -0,0 +1,22 @@
1
+ import {Trie} from '../../../../src';
2
+ import * as Benchmark from 'benchmark';
3
+ import {getRandomWords, magnitude} from '../../../utils';
4
+
5
+ const suite = new Benchmark.Suite();
6
+ const {HUNDRED_THOUSAND} = magnitude;
7
+ const trie = new Trie();
8
+ const randomWords = getRandomWords(HUNDRED_THOUSAND, false);
9
+
10
+ suite
11
+ .add(`${HUNDRED_THOUSAND} push`, () => {
12
+ for (let i = 0; i < randomWords.length; i++) {
13
+ trie.add(randomWords[i]);
14
+ }
15
+ })
16
+ .add(`${HUNDRED_THOUSAND} getWords`, () => {
17
+ for (let i = 0; i < randomWords.length; i++) {
18
+ trie.getWords(randomWords[i]);
19
+ }
20
+ });
21
+
22
+ export {suite};
@@ -0,0 +1,183 @@
1
+ import * as Benchmark from 'benchmark';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import * as fastGlob from 'fast-glob';
5
+ import {Color, numberFix, render} from '../utils';
6
+ import {PerformanceTest} from './types';
7
+
8
+ const reportDistPath = 'benchmark';
9
+ const testDir = path.join(__dirname, 'data-structures');
10
+ const testFiles = fastGlob.sync(path.join(testDir, '**', '*.test.ts'));
11
+
12
+ const report: {[key: string]: any} = {};
13
+
14
+ let completedCount = 0;
15
+
16
+ const performanceTests: PerformanceTest[] = [];
17
+ const {GREEN, BOLD, END, YELLOW, GRAY, CYAN, BG_YELLOW} = Color;
18
+
19
+ testFiles.forEach((file: string) => {
20
+ const testName = path.basename(file, '.test.ts');
21
+ const testFunction = require(file);
22
+ const {suite} = testFunction;
23
+ if (suite) performanceTests.push({testName, suite, file});
24
+ });
25
+
26
+ const composeReport = () => {
27
+ if (!fs.existsSync(reportDistPath)) fs.mkdirSync(reportDistPath, {recursive: true});
28
+
29
+ const filePath = path.join(reportDistPath, 'report.json');
30
+ const htmlFilePath = path.join(reportDistPath, 'report.html');
31
+ fs.writeFileSync(filePath, JSON.stringify(report, null, 2));
32
+ let html = `<!DOCTYPE html>
33
+ <html lang="en">
34
+ <head>
35
+ <meta charset="UTF-8">
36
+ <title>performance of data-structure-typed</title>
37
+ <style>
38
+ *{
39
+ box-sizing: border-box;
40
+ }
41
+ #json-to-html {
42
+ padding: 0 10px 20px;
43
+ }
44
+
45
+ .json-to-html-label {
46
+ font-size: 2rem;
47
+ margin: 2rem 0 0 3px;
48
+ }
49
+ .content table {
50
+ width: 100%;
51
+ table-layout: fixed;
52
+ border-collapse: collapse;
53
+ margin-top: 10px;
54
+ font-size: 16px;
55
+ }
56
+
57
+ .content table th,
58
+ .content table td {
59
+ padding: 8px 12px;
60
+ text-align: left;
61
+ border: 1px solid #ddd;
62
+ }
63
+
64
+ .content table th {
65
+ background-color: #f2f2f2;
66
+ font-weight: bold;
67
+ }
68
+
69
+ .content table tr:nth-child(odd) {
70
+ background-color: #ffffff;
71
+ }
72
+ </style>
73
+ </head>
74
+ <body>
75
+ <div id="json-to-html">`;
76
+ let htmlTables = '';
77
+ for (const r in report) {
78
+ if (report.hasOwnProperty(r)) {
79
+ htmlTables += render(report[r].testName, report[r].benchmarks, {
80
+ plainHtml: true,
81
+ '<>': 'table',
82
+ html: [
83
+ {
84
+ '<>': 'tr',
85
+ html: [
86
+ {'<>': 'td', html: '${name}'},
87
+ {'<>': 'td', html: '${periodMS}'},
88
+ {'<>': 'td', html: '${mean}'}
89
+ ]
90
+ }
91
+ ]
92
+ });
93
+ }
94
+ }
95
+ html += htmlTables;
96
+ html += `</div>
97
+ </body>
98
+ </html>`;
99
+ writeIntoMarkdown(htmlTables);
100
+ fs.writeFileSync(htmlFilePath, html);
101
+ console.log(`Performance ${BOLD}${GREEN}report${END} file generated`);
102
+ };
103
+
104
+ function writeIntoMarkdown(html: string) {
105
+ const parentDirectory = path.resolve(__dirname, '../..'); // The path to the parent directory
106
+ const markdownFilePath = path.join(parentDirectory, 'README.md'); // Path to README.md file
107
+ const textToInsert = html;
108
+
109
+ // Read the original README.md file
110
+ fs.readFile(markdownFilePath, 'utf8', (err, data) => {
111
+ if (err) {
112
+ console.error('Unable to read README.md file:', err);
113
+ return;
114
+ }
115
+
116
+ // Find the location in the README.md file where you want to insert the text, for example under a specific tag
117
+ const insertMarker = '## Benchmark';
118
+
119
+ const index = data.indexOf(insertMarker);
120
+ if (index === -1) {
121
+ console.error('Unable to find insertion point');
122
+ return;
123
+ }
124
+
125
+ // insert text
126
+ const updatedMarkdown =
127
+ data.slice(0, index + insertMarker.length) + '\n' + textToInsert + data.slice(index + insertMarker.length);
128
+
129
+ // Try writing the modified content back to the README.md file
130
+ fs.writeFile(markdownFilePath, updatedMarkdown, 'utf8', err => {
131
+ if (err) {
132
+ console.error('Unable to write to README.md file:', err);
133
+ } else {
134
+ console.log('The tables have been successfully inserted into the README.md file!');
135
+ }
136
+ });
137
+ });
138
+ }
139
+
140
+ performanceTests.forEach(item => {
141
+ const {suite, testName, file} = item;
142
+ const relativeFilePath = path.relative(__dirname, file);
143
+ const directory = path.dirname(relativeFilePath);
144
+ const fileName = path.basename(relativeFilePath);
145
+ console.log(`${BG_YELLOW}Running in${END}: ${GRAY}${directory}/${END}${CYAN}${fileName}${END}`);
146
+
147
+ if (suite) {
148
+ let runTime = 0;
149
+ suite
150
+ .on('complete', function (this: Benchmark.Suite) {
151
+ completedCount++;
152
+ report[testName] = {};
153
+ report[testName].benchmarks = this.map((benchmark: Benchmark) => {
154
+ runTime += benchmark.times.elapsed;
155
+ return {
156
+ 'test name': benchmark.name,
157
+ 'time taken (ms)': numberFix(benchmark.times.period * 1000, 2),
158
+ 'executions per sec': numberFix(benchmark.hz, 2),
159
+ 'executed times': numberFix(benchmark.count, 0),
160
+ 'sample mean (secs)': numberFix(benchmark.stats.mean, 2),
161
+ 'sample deviation': numberFix(benchmark.stats.deviation, 2)
162
+ };
163
+ });
164
+
165
+ report[testName].testName = testName;
166
+ const isDone = completedCount === performanceTests.length;
167
+ runTime = Number(runTime.toFixed(2));
168
+ const isTimeWarn = runTime > 120;
169
+ console.log(
170
+ // `Files: ${GREEN}${testFileCount}${END} `,
171
+ // `Suites: ${GREEN}${performanceTests.length}${END} `,
172
+ `Suites Progress: ${isDone ? GREEN : YELLOW}${completedCount}${END}/${isDone ? GREEN : YELLOW}${
173
+ performanceTests.length
174
+ }${END}`,
175
+ `Time: ${isTimeWarn ? YELLOW : GREEN}${runTime}s${END}`
176
+ );
177
+ if (isDone) {
178
+ composeReport();
179
+ }
180
+ })
181
+ .run({async: false});
182
+ }
183
+ });
@@ -0,0 +1 @@
1
+ export * from './reportor';
@@ -0,0 +1,3 @@
1
+ import * as Benchmark from 'benchmark';
2
+
3
+ export type PerformanceTest = {testName: string; suite: Benchmark.Suite; file: string};
@@ -1 +1,2 @@
1
1
  export * from './big-o';
2
+ export * from './json2html';
@@ -0,0 +1 @@
1
+ export type Json2htmlOptions = {plainHtml?: boolean} & Partial<{[key: string]: any}>;