fix: Remove export restrictions in package.json to enable ESModules to work properly.

This commit is contained in:
Revone 2024-11-30 19:29:37 +13:00
parent 8b247456f5
commit dd27393049
12 changed files with 1296 additions and 764 deletions

View file

@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.54.0](https://github.com/zrwusa/data-structure-typed/compare/v1.51.5...main) (upcoming)
## [v1.54.1](https://github.com/zrwusa/data-structure-typed/compare/v1.51.5...main) (upcoming)
### Changes

1609
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,23 +1,18 @@
{
"name": "data-structure-typed",
"version": "1.54.1",
"version": "1.54.2",
"description": "Javascript Data Structure. Heap, Binary Tree, Red Black Tree, Linked List, Deque, Trie, HashMap, Directed Graph, Undirected Graph, Binary Search Tree(BST), AVL Tree, Priority Queue, Graph, Queue, Tree Multiset, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue, Stack. Benchmark compared with C++ STL. API aligned with ES6 and Java.util. Usability is comparable to Python",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"browser": "dist/umd/data-structure-typed.min.js",
"types": "dist/esm/index.d.ts",
"umd:main": "dist/umd/data-structure-typed.min.js",
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
}
},
"scripts": {
"build": "npm run build:esm && npm run build:cjs && npm run build:umd && npm run build:docs-class",
"build": "npm run build:ecu && npm run build:docs-class",
"build:esm": "rm -rf dist/esm && tsc -p tsconfig-esm.json",
"build:cjs": "rm -rf dist/cjs && tsc -p tsconfig-cjs.json",
"build:umd": "tsup",
"build:ecu": "npm run build:esm && npm run build:cjs && npm run build:umd",
"build:docs": "npm run gen:examples && typedoc --out docs ./src",
"build:docs-class": "npm run gen:examples && typedoc --out docs ./src/data-structures",
"gen:examples": "ts-node scripts/testToExample.ts",

View file

@ -3,7 +3,7 @@ export * from './bst';
export * from './avl-tree';
export * from './segment-tree';
export * from './avl-tree-multi-map';
export * from './rb-tree';
export * from './red-black-tree';
export * from './tree-multi-map';
export * from './tree-counter';
export * from './avl-tree-counter';

View file

@ -1,3 +1,3 @@
import type { RedBlackTreeOptions } from './rb-tree';
import type { RedBlackTreeOptions } from './red-black-tree';
export type TreeCounterOptions<K, V, R> = RedBlackTreeOptions<K, V, R> & {};

View file

@ -1,3 +1,3 @@
import type { RedBlackTreeOptions } from './rb-tree';
import type { RedBlackTreeOptions } from './red-black-tree';
export type TreeMultiMapOptions<K, V, R> = Omit<RedBlackTreeOptions<K, V, R>, 'isMapMode'> & {}

View file

@ -0,0 +1,135 @@
import { AVLTree, BinaryTree, BST, Deque, DoublyLinkedList, HashMap, Heap, MaxPriorityQueue, MinHeap, MinPriorityQueue, Queue, RedBlackTree, SinglyLinkedList, Stack, TreeMultiMap, Trie } from 'data-structure-typed';
const orgArr = [6, 1, 2, 7, 5, 3, 4, 9, 8];
const orgStrArr = ['trie', 'trial', 'trick', 'trip', 'tree', 'trend', 'triangle', 'track', 'trace', 'transmit'];
const entries = [
[6, '6'],
[1, '1'],
[2, '2'],
[7, '7'],
[5, '5'],
[3, '3'],
[4, '4'],
[9, '9'],
[8, '8']
];
const queue = new Queue(orgArr);
queue.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const deque = new Deque(orgArr);
deque.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const sList = new SinglyLinkedList(orgArr);
sList.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const dList = new DoublyLinkedList(orgArr);
dList.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const stack = new Stack(orgArr);
stack.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const minHeap = new MinHeap(orgArr);
minHeap.print();
// [1, 5, 2, 7, 6, 3, 4, 9, 8]
const maxPQ = new MaxPriorityQueue(orgArr);
maxPQ.print();
// [9, 8, 4, 7, 5, 2, 3, 1, 6]
const biTree = new BinaryTree(entries);
biTree.print();
// ___6___
// / \
// ___1_ _2_
// / \ / \
// _7_ 5 3 4
// / \
// 9 8
const bst = new BST(entries);
bst.print();
// _____5___
// / \
// _2_ _7_
// / \ / \
// 1 3_ 6 8_
// \ \
// 4 9
const rbTree = new RedBlackTree(entries);
rbTree.print();
// ___4___
// / \
// _2_ _6___
// / \ / \
// 1 3 5 _8_
// / \
// 7 9
const avl = new AVLTree(entries);
avl.print();
// ___4___
// / \
// _2_ _6___
// / \ / \
// 1 3 5 _8_
// / \
// 7 9
const treeMulti = new TreeMultiMap(entries);
treeMulti.print();
// ___4___
// / \
// _2_ _6___
// / \ / \
// 1 3 5 _8_
// / \
// 7 9
const hm = new HashMap(entries);
hm.print();
// [[6, "6"], [1, "1"], [2, "2"], [7, "7"], [5, "5"], [3, "3"], [4, "4"], [9, "9"], [8, "8"]]
const rbTreeH = new RedBlackTree(hm);
rbTreeH.print();
// ___4___
// / \
// _2_ _6___
// / \ / \
// 1 3 5 _8_
// / \
// 7 9
const pq = new MinPriorityQueue(orgArr);
pq.print();
// [1, 5, 2, 7, 6, 3, 4, 9, 8]
const bst1 = new BST(pq);
bst1.print();
// _____5___
// / \
// _2_ _7_
// / \ / \
// 1 3_ 6 8_
// \ \
// 4 9
const dq1 = new Deque(orgArr);
dq1.print();
// [6, 1, 2, 7, 5, 3, 4, 9, 8]
const rbTree1 = new RedBlackTree(dq1);
rbTree1.print();
// _____5___
// / \
// _2___ _7___
// / \ / \
// 1 _4 6 _9
// / /
// 3 8
const trie2 = new Trie(orgStrArr);
trie2.print();
// ['trie', 'trial', 'triangle', 'trick', 'trip', 'tree', 'trend', 'track', 'trace', 'transmit']
const heap2 = new Heap(trie2, { comparator: (a, b) => Number(a) - Number(b) });
heap2.print();
// ['transmit', 'trace', 'tree', 'trend', 'track', 'trial', 'trip', 'trie', 'trick', 'triangle']
const dq2 = new Deque(heap2);
dq2.print();
// ['transmit', 'trace', 'tree', 'trend', 'track', 'trial', 'trip', 'trie', 'trick', 'triangle']
const entries2 = dq2.map((el, i) => [i, el]);
const avl2 = new AVLTree(entries2);
avl2.print();
// ___3_______
// / \
// _1_ ___7_
// / \ / \
// 0 2 _5_ 8_
// / \ \
// 4 6 9

View file

@ -0,0 +1,45 @@
import { AVLTree } from '../../../../';
import * as Benchmark from 'benchmark';
// import { getRandomIntArray, magnitude } from '../../../utils';
// const suite = new Benchmark.Suite();
// const avlTree = new AVLTree();
// const { HUNDRED_THOUSAND } = magnitude;
// const randomArray = getRandomIntArray(HUNDRED_THOUSAND, 0, HUNDRED_THOUSAND - 1, true);
// suite
// .add(`${HUNDRED_THOUSAND.toLocaleString()} add randomly`, () => {
// avlTree.clear();
// for (let i = 0; i < randomArray.length; i++)
// avlTree.add(randomArray[i]);
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} add`, () => {
// avlTree.clear();
// for (let i = 0; i < randomArray.length; i++)
// avlTree.add(i);
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} get`, () => {
// for (let i = 0; i < randomArray.length; i++)
// avlTree.get(randomArray[i]);
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} getNode`, () => {
// for (let i = 0; i < randomArray.length; i++)
// avlTree.getNode(randomArray[i]);
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} iterator`, () => {
// const entries = [...avlTree];
// return entries.length === HUNDRED_THOUSAND;
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} add & delete orderly`, () => {
// avlTree.clear();
// for (let i = 0; i < randomArray.length; i++)
// avlTree.add(i);
// for (let i = 0; i < randomArray.length; i++)
// avlTree.delete(i);
// })
// .add(`${HUNDRED_THOUSAND.toLocaleString()} add & delete randomly`, () => {
// avlTree.clear();
// for (let i = 0; i < randomArray.length; i++)
// avlTree.add(randomArray[i]);
// for (let i = 0; i < randomArray.length; i++)
// avlTree.delete(randomArray[i]);
// });
// export { suite };

View file

@ -0,0 +1,248 @@
import * as path from 'path';
import * as fs from 'fs';
import * as fastGlob from 'fast-glob';
import { ConsoleColor, numberFix, render } from '../utils';
const args = process.argv.slice(2);
const { GREEN, BOLD, END, YELLOW, GRAY, CYAN, BG_YELLOW } = ConsoleColor;
const isOnlyOrdered = true;
const runOrder = [
'heap',
'avl-tree',
'rb-tree',
'doubly-linked-list',
'directed-graph',
'queue',
'deque',
'hash-map',
'trie',
'stack'
// 'singly-linked-list',
// 'priority-queue',
// 'binary-tree-overall'
];
const getRelativePath = file => {
return path.relative(__dirname, file);
};
const coloredLabeled = (label, file) => {
const relativeFilePath = getRelativePath(file);
const directory = path.dirname(relativeFilePath);
const fileName = path.basename(relativeFilePath);
return `${BG_YELLOW} ${label} ${END} ${GRAY}${directory}/${END}${CYAN}${fileName}${END}`;
};
const parentDirectory = path.resolve(__dirname, '../..');
const reportDistPath = path.join(parentDirectory, 'benchmark');
const testDir = path.join(__dirname, 'data-structures');
const allFiles = fastGlob.sync(path.join(testDir, '**', '*.test.js'));
let testFiles;
let isIndividual = false;
if (args.length > 0) {
console.log(`arguments: ${args.join(' ')}`);
testFiles = allFiles.filter(file => args.every(word => file.includes(word)));
isIndividual = true;
console.log(
`${testFiles.map(file => coloredLabeled('Found', file)).join(`
`)}`
);
} else {
isIndividual = false;
testFiles = allFiles;
}
const report = {};
let completedCount = 0;
const performanceTests = [];
testFiles.forEach(file => {
const testName = path.basename(file, '.test.ts');
const testFunction = require(file);
const { suite } = testFunction;
if (suite)
performanceTests.push({
testName,
suite,
file
});
});
const composeReport = () => {
if (!fs.existsSync(reportDistPath))
fs.mkdirSync(reportDistPath, {
recursive: true
});
const filePath = path.join(reportDistPath, 'report.json');
const htmlFilePath = path.join(reportDistPath, 'report.html');
fs.writeFileSync(filePath, JSON.stringify(report, null, 2));
let html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>performance of data-structure-typed</title>
<style>
*{
box-sizing: border-box;
}
#json-to-html {
padding: 0 10px 20px;
}
.json-to-html-label {
font-size: 2rem;
margin: 2rem 0 0 3px;
}
.content table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
margin-top: 10px;
font-size: 16px;
}
.content table th,
.content table td {
padding: 8px 12px;
text-align: left;
border: 1px solid #ddd;
}
.content table th {
background-color: #f2f2f2;
font-weight: bold;
}
.content table tr:nth-child(odd) {
background-color: #ffffff;
}
</style>
</head>
<body>
<div id="json-to-html">`;
let htmlTables = '';
for (const r in report) {
if (report.hasOwnProperty(r)) {
htmlTables += render(report[r].testName, report[r].benchmarks, {
plainHtml: true,
'<>': 'table',
html: [
{
'<>': 'tr',
html: [
{
'<>': 'td',
html: '${name}'
},
{
'<>': 'td',
html: '${periodMS}'
},
{
'<>': 'td',
html: '${mean}'
}
]
}
]
});
}
}
htmlTables += `
`;
html += htmlTables;
html += `</div>
</body>
</html>`;
if (!isIndividual)
replaceMarkdownContent(
'[//]: # (No deletion!!! Start of Replace Section)', // Start tag
'[//]: # (No deletion!!! End of Replace Section)', // end identifier
htmlTables // New content to be inserted
);
fs.writeFileSync(htmlFilePath, html);
console.log(`Performance ${BOLD}${GREEN}report${END} file generated in file://${BOLD}${GREEN}${htmlFilePath}${END}`);
};
function replaceMarkdownContent(startMarker, endMarker, newText) {
const filePath = path.join(parentDirectory, 'README.md'); // Path to README.md file
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error(`Unable to read ${filePath}:`, err);
return;
}
// Find the start and end markers in the content
const startIndex = data.indexOf(startMarker);
const endIndex = data.indexOf(endMarker, startIndex + 1);
if (startIndex === -1 || endIndex === -1) {
console.error('Unable to find start or end marker');
return;
}
// Replace the old content with the new text
const updatedMarkdown = data.slice(0, startIndex + startMarker.length) + '\n' + newText + data.slice(endIndex);
// Try writing the modified content back to the file
fs.writeFile(filePath, updatedMarkdown, 'utf8', err => {
if (err) {
console.error(`Unable to write to ${filePath}:`, err);
} else {
console.log(`The content has been successfully replaced in file://${BOLD}${GREEN}${filePath}${END}`);
}
});
});
}
const sortedPerformanceTests = (
isOnlyOrdered ? [...performanceTests].filter(test => runOrder.includes(test.testName)) : [...performanceTests]
).sort((a, b) => {
const indexA = runOrder.indexOf(a.testName);
const indexB = runOrder.indexOf(b.testName);
// If both a and b are in the runOrder, sort them according to their indices in the runOrder.
if (indexA !== -1 && indexB !== -1) {
return indexA - indexB;
}
// If there is only 'a' in the runOrder, then place 'b' in front.
if (indexA !== -1) {
return 1;
}
// If only b is in the runOrder, then a should be placed before it.
if (indexB !== -1) {
return -1;
}
// If neither a nor b are in runOrder, keep their original runOrder
return 0;
});
console.log(
`${GREEN} Matched Suites (${performanceTests.length})${END}: ${performanceTests.map(test => test.testName)}`
);
console.log(
`${GREEN} Running Suites (${sortedPerformanceTests.length})${END}: ${sortedPerformanceTests.map(test => test.testName)}`
);
sortedPerformanceTests.forEach(item => {
const { suite, testName, file } = item;
console.log(coloredLabeled('Running', file));
if (suite) {
let runTime = 0;
suite
.on('complete', function () {
completedCount++;
report[testName] = {};
report[testName].benchmarks = this.map(benchmark => {
runTime += benchmark.times.elapsed;
return {
'test name': benchmark.name,
'time taken (ms)': numberFix(benchmark.times.period * 1000, 2),
// 'executions per sec': numberFix(benchmark.hz, 2),
// 'executed times': numberFix(benchmark.count, 0),
'sample mean (secs)': numberFix(benchmark.stats.mean, 2),
'sample deviation': numberFix(benchmark.stats.deviation, 2)
};
});
report[testName].testName = testName;
const isDone = completedCount === sortedPerformanceTests.length;
runTime = Number(runTime.toFixed(2));
const isTimeWarn = runTime > 120;
console.log(
// `Files: ${GREEN}${testFileCount}${END} `,
// `Suites: ${GREEN}${performanceTests.length}${END} `,
`Suites Progress: ${isDone ? GREEN : YELLOW}${completedCount}${END}/${isDone ? GREEN : YELLOW}${sortedPerformanceTests.length}${END}`,
`Time Costs: ${isTimeWarn ? YELLOW : GREEN}${runTime}s${END}`
);
if (isDone) {
composeReport();
}
})
.run({ async: false });
}
});

View file

@ -435,7 +435,7 @@ describe('AVLTreeMultiMap iterative methods test', () => {
});
it('map should return a new avlTmm with modified elements', () => {
const avlTmmMapped = avlTmm.map((key, value) => [(key * 2).toString(), value ? value :[]]);
const avlTmmMapped = avlTmm.map((key, value) => [(key * 2).toString(), value ? value : []]);
expect(avlTmmMapped.size).toBe(3);
expect([...avlTmmMapped]).toEqual([
['2', ['a']],

View file

@ -664,7 +664,7 @@ describe('TreeMultiMap 2', () => {
});
it('map should return a new tmm with modified elements', () => {
const tmmMapped = tmm.map((key, value) => [(key * 2).toString(), value ? value :[]]);
const tmmMapped = tmm.map((key, value) => [(key * 2).toString(), value ? value : []]);
expect(tmmMapped.size).toBe(3);
expect([...tmmMapped]).toEqual([
['2', ['a']],