diff --git a/CHANGELOG.md b/CHANGELOG.md index ceecc29..1d6dfb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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.53.5](https://github.com/zrwusa/data-structure-typed/compare/v1.51.5...main) (upcoming) +## [v1.53.6](https://github.com/zrwusa/data-structure-typed/compare/v1.51.5...main) (upcoming) ### Changes diff --git a/package-lock.json b/package-lock.json index 7c5d51d..319f1dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "data-structure-typed", - "version": "1.53.5", + "version": "1.53.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "data-structure-typed", - "version": "1.53.5", + "version": "1.53.6", "license": "MIT", "devDependencies": { "@eslint/compat": "^1.2.2", @@ -19,11 +19,11 @@ "@typescript-eslint/eslint-plugin": "^8.12.1", "@typescript-eslint/parser": "^8.12.1", "auto-changelog": "^2.5.0", - "avl-tree-typed": "^1.53.4", + "avl-tree-typed": "^1.53.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.53.4", - "bst-typed": "^1.53.4", - "data-structure-typed": "^1.53.4", + "binary-tree-typed": "^1.53.5", + "bst-typed": "^1.53.5", + "data-structure-typed": "^1.53.5", "dependency-cruiser": "^16.5.0", "doctoc": "^2.2.1", "eslint": "^9.13.0", @@ -32,7 +32,7 @@ "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-import": "^2.31.0", "fast-glob": "^3.3.2", - "heap-typed": "^1.53.4", + "heap-typed": "^1.53.5", "istanbul-badges-readme": "^1.9.0", "jest": "^29.7.0", "js-sdsl": "^4.4.2", @@ -3437,13 +3437,13 @@ } }, "node_modules/avl-tree-typed": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.53.4.tgz", - "integrity": "sha512-dZMEutl5xMp/n54V6W6SugCXdmfcgy+6esqlpjG47nQfrQ3WMQzx2oytMWRZa6Y+nDtDNefbwlEOO/fLKZUHyQ==", + "version": "1.53.5", + "resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.53.5.tgz", + "integrity": "sha512-BkJgD5S4ALEl4ytKKVvqz3Qo/19U2bxnOUyZxy3dMgXNh20vaPZAJ82bFRX2lAoBFBDmIgtWp/klxC0CrDO6nQ==", "dev": true, "license": "MIT", "dependencies": { - "data-structure-typed": "^1.53.4" + "data-structure-typed": "^1.53.5" } }, "node_modules/babel-jest": { @@ -3602,13 +3602,13 @@ } }, "node_modules/binary-tree-typed": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.53.4.tgz", - "integrity": "sha512-/yDQUWHdT1HQBkMVTGZuo+Nn/nx1JnV5ERBFIKCdDVBvG2qKmTa5RlSC7rnjLzLsQz28qVHvisjoRYBhcQpCWg==", + "version": "1.53.5", + "resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.53.5.tgz", + "integrity": "sha512-4DSrFAlykAMRF2w/hqaPG+vzsQLKq8TTnVBTD2c9Ew680+jHcanypDb6mzW0WJWSgA+v5V9IEX7P6Zz6/vS1rg==", "dev": true, "license": "MIT", "dependencies": { - "data-structure-typed": "^1.53.4" + "data-structure-typed": "^1.53.5" } }, "node_modules/brace-expansion": { @@ -3691,13 +3691,13 @@ } }, "node_modules/bst-typed": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.53.4.tgz", - "integrity": "sha512-hjTK/CcW2hw0yAtazhFOl7lsNq598FuNwCgbcjpFgXk51swLwJ5P5Sm70UzwVns1LSdIulTK49zil9tGs6zv1g==", + "version": "1.53.5", + "resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.53.5.tgz", + "integrity": "sha512-poYNwY4rwHinpNCQDsTv631XGUNJh/wvklLzaok+Nt+XV1PsH2e8VATaTCUMdTwLFrDn7jGFoY8mJkJjmr0s2w==", "dev": true, "license": "MIT", "dependencies": { - "data-structure-typed": "^1.53.4" + "data-structure-typed": "^1.53.5" } }, "node_modules/buffer-from": { @@ -4069,9 +4069,9 @@ } }, "node_modules/data-structure-typed": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.53.4.tgz", - "integrity": "sha512-sMmlWv2wMqUVPnBemYc7RQMYtM0AXQq0m9drVeu0eMtpSvojvFb4hW+hzpd6IBtULguNw2YBG9EyNo7irlpavQ==", + "version": "1.53.5", + "resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.53.5.tgz", + "integrity": "sha512-v7gFtZe71/vS/+HR+eK3EZmljvp5ANJK3DiCjdLC5XGmzpLvJVwfYz+An9f8+FEoM6DXrKLAdDkZPU9m/hZW7g==", "dev": true, "license": "MIT" }, @@ -5946,13 +5946,13 @@ } }, "node_modules/heap-typed": { - "version": "1.53.4", - "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.53.4.tgz", - "integrity": "sha512-/lktvgpfH7Y2q8XpMFYCEebRIo5nM85DCR19zUeo3soVrxa2H90vJAKJJ0cPP/DEJ2cDggMk/Cuo4k4LLhbf7A==", + "version": "1.53.5", + "resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.53.5.tgz", + "integrity": "sha512-H5Vj0U+fXyvdyW5rSZ44kOI7WeThzaNihhwD7kQ+SkTjM9+sskUvx6JpZf62ca56NRt+57w42gg6A/A3S8W0bA==", "dev": true, "license": "MIT", "dependencies": { - "data-structure-typed": "^1.53.4" + "data-structure-typed": "^1.53.5" } }, "node_modules/html-escaper": { diff --git a/package.json b/package.json index 08779bc..d10b485 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.53.5", + "version": "1.53.6", "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/mjs/index.js", @@ -20,7 +20,7 @@ "build:umd": "tsup", "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 testToExample.ts", + "gen:examples": "ts-node scripts/testToExample.ts", "test:in-band": "jest --runInBand", "test": "npm run test:in-band", "test:integration": "npm run update:subs && jest --config jest.integration.config.js", @@ -35,7 +35,7 @@ "format:test": "prettier --write 'test/**/*.{js,ts}'", "format": "npm run format:src && npm run format:test", "check:exist-latest": "sh scripts/check_exist_remotely.sh", - "ci": "env && git fetch --tags && npm run update:subs && npm run inspect && npm run lint && npm run build && npm run test && npm run changelog", + "ci": "env && git fetch --tags && npm run update:subs && npm run inspect && npm run lint && npm run test && npm run changelog", "update:subs": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed data-structure-typed --save-dev", "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-multimap-typed trie-typed undirected-graph-typed queue-typed --save-dev", "changelog": "auto-changelog", @@ -70,11 +70,11 @@ "@typescript-eslint/eslint-plugin": "^8.12.1", "@typescript-eslint/parser": "^8.12.1", "auto-changelog": "^2.5.0", - "avl-tree-typed": "^1.53.4", + "avl-tree-typed": "^1.53.5", "benchmark": "^2.1.4", - "binary-tree-typed": "^1.53.4", - "bst-typed": "^1.53.4", - "data-structure-typed": "^1.53.4", + "binary-tree-typed": "^1.53.5", + "bst-typed": "^1.53.5", + "data-structure-typed": "^1.53.5", "dependency-cruiser": "^16.5.0", "doctoc": "^2.2.1", "eslint": "^9.13.0", @@ -83,7 +83,7 @@ "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-import": "^2.31.0", "fast-glob": "^3.3.2", - "heap-typed": "^1.53.4", + "heap-typed": "^1.53.5", "istanbul-badges-readme": "^1.9.0", "jest": "^29.7.0", "js-sdsl": "^4.4.2", diff --git a/testToExample.ts b/scripts/testToExample.ts similarity index 85% rename from testToExample.ts rename to scripts/testToExample.ts index 4f12041..a2c6891 100644 --- a/testToExample.ts +++ b/scripts/testToExample.ts @@ -1,13 +1,27 @@ +// @ts-ignore import fs from 'fs'; +// @ts-ignore import path from 'path'; import * as ts from 'typescript'; -import { toPascalCase } from './test/utils'; + +const filePath = path.resolve(__dirname, './config.json'); +const fileContent = fs.readFileSync(filePath, 'utf-8'); +const config = JSON.parse(fileContent); + +function toPascalCase(str: string): string { + return str + .replace(/([a-z])([A-Z])/g, '$1 $2') // Add space between lowercase and uppercase letters + .replace(/[^a-zA-Z0-9]+/g, ' ') // Replace non-alphanumeric characters with spaces + .split(' ') // Separate strings by spaces + .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()) // The first letter is capitalized, the rest are lowercase + .join(''); // Combine into a string +} const isReplaceMD = true; const START_MARKER = '[//]: # (No deletion!!! Start of Example Replace Section)'; const END_MARKER = '[//]: # (No deletion!!! End of Example Replace Section)'; -const pkgRootDir = '/Users/revone/projects/data-structure-typed-individuals'; +const pkgRootDir = config.individualsDir; const dirMap: Record = { Heap: "heap-typed", AvlTree: "avl-tree-typed", @@ -93,6 +107,7 @@ function extractExamplesFromFile(filePath: string): { name: string; body: string } ) .replace( + // @ts-ignore /expect\((.*?)\)\.(toEqual|toBe|toStrictEqual|toHaveLength|toMatchObject)\((.*?)\);/gs, // Use `s` flag for multiline (match, actual, method, expected) => { expected = expected.replace(/\n/g, '\n //') @@ -151,11 +166,15 @@ function addExamplesToSourceFile( // Replace @example part const exampleSection = examples .map( - example => - ` * @example \n * \/\/ ${example.name} \n${example.body + example => { + const indentedBody = ' ' + example.body; + return ` * @example\n * \/\/ ${example.name}\n${indentedBody .split('\n') - .map(line => ` * ${line}`) + .map(line => { + if (line.trim() === '') return ` *` + return ` * ${line}`}) .join('\n')}` + } ) .join('\n') + '\n '; @@ -163,7 +182,7 @@ function addExamplesToSourceFile( if (existingCommentInner.includes('@example')) { newComment = existingCommentInner.replace(/ \* @example[\s\S]*?(?=\*\/|$)/g, exampleSection); } else { - newComment = existingCommentInner + `${exampleSection}`; + newComment = existingCommentInner + `${exampleSection.trimStart()}`; } @@ -210,7 +229,9 @@ function updateExamples(testDir: string, sourceBaseDir: string): void { const newExamples = examples.map( - example => `### ${example.name}\n\`\`\`typescript\n${example.body}\n\`\`\`` + example => { + const indentedBody = ' ' + example.body; + return `### ${example.name}\n\`\`\`typescript\n${indentedBody}\n\`\`\``} ); if (isReplaceMD && newExamples.length > 0) { @@ -252,7 +273,7 @@ function replaceExamplesInReadme(readmePath: string, newExamples: string[]): voi } // Run the script -const testDir = path.resolve(__dirname, 'test/unit'); -const sourceBaseDir = path.resolve(__dirname, 'src'); +const testDir = path.resolve(__dirname, '../test/unit'); +const sourceBaseDir = path.resolve(__dirname, '../src'); updateExamples(testDir, sourceBaseDir); diff --git a/src/data-structures/heap/heap.ts b/src/data-structures/heap/heap.ts index f75bc1f..f41ed7a 100644 --- a/src/data-structures/heap/heap.ts +++ b/src/data-structures/heap/heap.ts @@ -21,7 +21,7 @@ import { IterableElementBase } from '../base'; * 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prime's minimum-spanning tree algorithm, which use heaps to improve performance. * @example * // Use Heap to sort an array - * function heapSort(arr: number[]): number[] { + * function heapSort(arr: number[]): number[] { * const heap = new Heap(arr, { comparator: (a, b) => a - b }); * const sorted: number[] = []; * while (!heap.isEmpty()) { @@ -34,7 +34,7 @@ import { IterableElementBase } from '../base'; * console.log(heapSort(array)); // [1, 2, 3, 4, 5, 8] * @example * // Use Heap to solve top k problems - * function topKElements(arr: number[], k: number): number[] { + * function topKElements(arr: number[], k: number): number[] { * const heap = new Heap([], { comparator: (a, b) => b - a }); // Max heap * arr.forEach(num => { * heap.add(num); @@ -47,7 +47,7 @@ import { IterableElementBase } from '../base'; * console.log(topKElements(numbers, 3)); // [15, 10, 5] * @example * // Use Heap to merge sorted sequences - * function mergeSortedSequences(sequences: number[][]): number[] { + * function mergeSortedSequences(sequences: number[][]): number[] { * const heap = new Heap<{ value: number; seqIndex: number; itemIndex: number }>([], { * comparator: (a, b) => a.value - b.value // Min heap * }); @@ -84,7 +84,7 @@ import { IterableElementBase } from '../base'; * console.log(mergeSortedSequences(sequences)); // [1, 2, 3, 4, 5, 6, 7, 8, 9] * @example * // Use Heap to dynamically maintain the median - * class MedianFinder { + * class MedianFinder { * private low: MaxHeap; // Max heap, stores the smaller half * private high: MinHeap; // Min heap, stores the larger half * @@ -121,7 +121,7 @@ import { IterableElementBase } from '../base'; * console.log(medianFinder.findMedian()); // 30 * @example * // Use Heap for load balancing - * function loadBalance(requests: number[], servers: number): number[] { + * function loadBalance(requests: number[], servers: number): number[] { * const serverHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // min heap * const serverLoads = new Array(servers).fill(0); * @@ -143,7 +143,7 @@ import { IterableElementBase } from '../base'; * console.log(loadBalance(requests, 3)); // [12, 8, 5] * @example * // Use Heap to schedule tasks - * type Task = [string, number]; + * type Task = [string, number]; * * function scheduleTasks(tasks: Task[], machines: number): Map { * const machineHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // Min heap diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 7f788c5..e7cbbd7 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -82,13 +82,13 @@ export class DoublyLinkedListNode { } /** - * 1. Node Structure: Each node contains three parts: a data field, a pointer (or reference) to the previous node, and a pointer to the next node. This structure allows traversal of the linked list in both directions. + *1. Node Structure: Each node contains three parts: a data field, a pointer (or reference) to the previous node, and a pointer to the next node. This structure allows traversal of the linked list in both directions. * 2. Bidirectional Traversal: Unlike singly linked lists, doubly linked lists can be easily traversed forwards or backwards. This makes insertions and deletions in the list more flexible and efficient. * 3. No Centralized Index: Unlike arrays, elements in a linked list are not stored contiguously, so there is no centralized index. Accessing elements in a linked list typically requires traversing from the head or tail node. * 4. High Efficiency in Insertion and Deletion: Adding or removing elements in a linked list does not require moving other elements, making these operations more efficient than in arrays. * @example * // text editor operation history - * const actions = [ + * const actions = [ * { type: 'insert', content: 'first line of text' }, * { type: 'insert', content: 'second line of text' }, * { type: 'delete', content: 'delete the first line' } @@ -100,7 +100,7 @@ export class DoublyLinkedListNode { * console.log(editorHistory.last?.type); // 'insert' * @example * // Browser history - * const browserHistory = new DoublyLinkedList(); + * const browserHistory = new DoublyLinkedList(); * * browserHistory.push('home page'); * browserHistory.push('search page'); @@ -111,7 +111,7 @@ export class DoublyLinkedListNode { * console.log(browserHistory.last); // 'search page' * @example * // Use DoublyLinkedList to implement music player - * // Define the Song interface + * // Define the Song interface * interface Song { * title: string; * artist: string; @@ -236,7 +236,7 @@ export class DoublyLinkedListNode { * // ] * @example * // Use DoublyLinkedList to implement LRU cache - * interface CacheEntry { + * interface CacheEntry { * key: K; * value: V; * } @@ -398,7 +398,7 @@ export class DoublyLinkedListNode { * console.log(cache.isEmpty); // true * @example * // finding lyrics by timestamp in Coldplay's "Fix You" - * // Create a DoublyLinkedList to store song lyrics with timestamps + * // Create a DoublyLinkedList to store song lyrics with timestamps * const lyricsList = new DoublyLinkedList<{ time: number; text: string }>(); * * // Detailed lyrics with precise timestamps (in milliseconds) @@ -438,7 +438,7 @@ export class DoublyLinkedListNode { * console.log(lateTimeLyric?.text); // 'And I will try to fix you' * @example * // cpu process schedules - * class Process { + * class Process { * constructor( * public id: number, * public priority: number