data-structure-typed 1.53.5 → 1.53.7
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.
- package/CHANGELOG.md +1 -1
- package/README.md +16 -25
- package/benchmark/report.html +32 -5
- package/benchmark/report.json +326 -23
- package/dist/cjs/common/index.d.ts +12 -0
- package/dist/cjs/common/index.js +24 -0
- package/dist/cjs/common/index.js.map +1 -0
- package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js +7 -10
- package/dist/cjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/avl-tree.js +2 -2
- package/dist/cjs/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/binary-tree.d.ts +54 -19
- package/dist/cjs/data-structures/binary-tree/binary-tree.js +100 -66
- package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/bst.d.ts +100 -36
- package/dist/cjs/data-structures/binary-tree/bst.js +185 -66
- package/dist/cjs/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/rb-tree.d.ts +4 -0
- package/dist/cjs/data-structures/binary-tree/rb-tree.js +6 -2
- package/dist/cjs/data-structures/binary-tree/rb-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js +2 -2
- package/dist/cjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
- package/dist/cjs/data-structures/heap/heap.d.ts +6 -6
- package/dist/cjs/data-structures/heap/heap.js +6 -6
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.d.ts +31 -19
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.js +49 -34
- package/dist/cjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
- package/dist/cjs/data-structures/linked-list/singly-linked-list.d.ts +144 -62
- package/dist/cjs/data-structures/linked-list/singly-linked-list.js +201 -97
- package/dist/cjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
- package/dist/cjs/data-structures/trie/trie.d.ts +110 -4
- package/dist/cjs/data-structures/trie/trie.js +122 -12
- package/dist/cjs/data-structures/trie/trie.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
- package/dist/cjs/types/data-structures/binary-tree/bst.d.ts +3 -2
- package/dist/cjs/types/data-structures/binary-tree/rb-tree.d.ts +1 -1
- package/dist/cjs/types/utils/utils.d.ts +10 -6
- package/dist/cjs/utils/utils.js +4 -2
- package/dist/cjs/utils/utils.js.map +1 -1
- package/dist/mjs/common/index.d.ts +12 -0
- package/dist/mjs/common/index.js +24 -0
- package/dist/mjs/common/index.js.map +1 -0
- package/dist/mjs/data-structures/binary-tree/avl-tree-multi-map.js +8 -10
- package/dist/mjs/data-structures/binary-tree/avl-tree-multi-map.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/avl-tree.js +3 -2
- package/dist/mjs/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/binary-tree.d.ts +54 -19
- package/dist/mjs/data-structures/binary-tree/binary-tree.js +95 -61
- package/dist/mjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/bst.d.ts +100 -36
- package/dist/mjs/data-structures/binary-tree/bst.js +187 -66
- package/dist/mjs/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/rb-tree.d.ts +4 -0
- package/dist/mjs/data-structures/binary-tree/rb-tree.js +6 -2
- package/dist/mjs/data-structures/binary-tree/rb-tree.js.map +1 -1
- package/dist/mjs/data-structures/binary-tree/tree-multi-map.js +2 -2
- package/dist/mjs/data-structures/binary-tree/tree-multi-map.js.map +1 -1
- package/dist/mjs/data-structures/heap/heap.d.ts +6 -6
- package/dist/mjs/data-structures/heap/heap.js +6 -6
- package/dist/mjs/data-structures/linked-list/doubly-linked-list.d.ts +31 -19
- package/dist/mjs/data-structures/linked-list/doubly-linked-list.js +49 -34
- package/dist/mjs/data-structures/linked-list/doubly-linked-list.js.map +1 -1
- package/dist/mjs/data-structures/linked-list/singly-linked-list.d.ts +144 -62
- package/dist/mjs/data-structures/linked-list/singly-linked-list.js +201 -97
- package/dist/mjs/data-structures/linked-list/singly-linked-list.js.map +1 -1
- package/dist/mjs/data-structures/trie/trie.d.ts +110 -4
- package/dist/mjs/data-structures/trie/trie.js +122 -12
- package/dist/mjs/data-structures/trie/trie.js.map +1 -1
- package/dist/mjs/index.d.ts +1 -1
- package/dist/mjs/index.js +1 -1
- package/dist/mjs/index.js.map +1 -1
- package/dist/mjs/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
- package/dist/mjs/types/data-structures/binary-tree/bst.d.ts +3 -2
- package/dist/mjs/types/data-structures/binary-tree/rb-tree.d.ts +1 -1
- package/dist/mjs/types/utils/utils.d.ts +10 -6
- package/dist/mjs/utils/utils.js +4 -2
- package/dist/mjs/utils/utils.js.map +1 -1
- package/dist/umd/data-structure-typed.js +512 -266
- package/dist/umd/data-structure-typed.min.js +2 -2
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +8 -8
- package/src/common/index.ts +19 -0
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +7 -9
- package/src/data-structures/binary-tree/avl-tree.ts +3 -2
- package/src/data-structures/binary-tree/binary-tree.ts +108 -64
- package/src/data-structures/binary-tree/bst.ts +190 -69
- package/src/data-structures/binary-tree/rb-tree.ts +6 -2
- package/src/data-structures/binary-tree/tree-multi-map.ts +3 -3
- package/src/data-structures/heap/heap.ts +39 -39
- package/src/data-structures/linked-list/doubly-linked-list.ts +139 -121
- package/src/data-structures/linked-list/singly-linked-list.ts +219 -98
- package/src/data-structures/trie/trie.ts +116 -11
- package/src/index.ts +1 -1
- package/src/types/data-structures/binary-tree/binary-tree.ts +1 -1
- package/src/types/data-structures/binary-tree/bst.ts +3 -2
- package/src/types/data-structures/binary-tree/rb-tree.ts +1 -1
- package/src/types/utils/utils.ts +16 -10
- package/src/utils/utils.ts +4 -2
- package/test/performance/data-structures/binary-tree/avl-tree.test.ts +3 -0
- package/test/performance/data-structures/binary-tree/rb-tree.test.ts +4 -1
- package/test/performance/reportor.ts +38 -33
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +2 -2
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +12 -12
- package/test/unit/data-structures/binary-tree/bst.test.ts +79 -3
- package/test/unit/data-structures/binary-tree/overall.test.ts +14 -22
- package/test/unit/data-structures/binary-tree/rb-tree.test.ts +100 -1
- package/test/unit/data-structures/trie/trie.test.ts +151 -0
- package/test/unit/utils/utils.test.ts +6 -6
- package/dist/cjs/constants/index.d.ts +0 -4
- package/dist/cjs/constants/index.js +0 -9
- package/dist/cjs/constants/index.js.map +0 -1
- package/dist/mjs/constants/index.d.ts +0 -4
- package/dist/mjs/constants/index.js +0 -6
- package/dist/mjs/constants/index.js.map +0 -1
- package/src/constants/index.ts +0 -4
- package/testToExample.ts +0 -215
|
@@ -932,3 +932,154 @@ describe('Trie class', () => {
|
|
|
932
932
|
expect(trieB.hasPrefix('ap')).toBe(false);
|
|
933
933
|
});
|
|
934
934
|
});
|
|
935
|
+
|
|
936
|
+
describe('Trie basic', () => {
|
|
937
|
+
test('Dictionary: Basic word lookup functionality', () => {
|
|
938
|
+
// Initialize a new Trie and add dictionary words
|
|
939
|
+
const dictionary = new Trie<string>();
|
|
940
|
+
const words = ['apple', 'app', 'application', 'approve', 'bread', 'break'];
|
|
941
|
+
words.forEach(word => dictionary.add(word));
|
|
942
|
+
|
|
943
|
+
// Test exact word matches
|
|
944
|
+
expect(dictionary.has('apple')).toBe(true);
|
|
945
|
+
expect(dictionary.has('app')).toBe(true);
|
|
946
|
+
expect(dictionary.has('bread')).toBe(true);
|
|
947
|
+
|
|
948
|
+
// Test non-existent words
|
|
949
|
+
expect(dictionary.has('appl')).toBe(false);
|
|
950
|
+
expect(dictionary.has('breaking')).toBe(false);
|
|
951
|
+
|
|
952
|
+
// Verify dictionary size
|
|
953
|
+
expect(dictionary.size).toBe(words.length);
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
test('Autocomplete: Limited suggestions with max results', () => {
|
|
957
|
+
const autocomplete = new Trie<string>();
|
|
958
|
+
|
|
959
|
+
// Add city names
|
|
960
|
+
const cities = ['New York', 'New Orleans', 'New Delhi', 'New Jersey', 'New Mexico', 'New Hampshire'];
|
|
961
|
+
|
|
962
|
+
cities.forEach(city => autocomplete.add(city));
|
|
963
|
+
|
|
964
|
+
// Get limited number of suggestions
|
|
965
|
+
const maxSuggestions = 3;
|
|
966
|
+
const suggestions = autocomplete.getWords('New', maxSuggestions);
|
|
967
|
+
|
|
968
|
+
expect(suggestions.length).toBe(maxSuggestions);
|
|
969
|
+
suggestions.forEach(suggestion => {
|
|
970
|
+
expect(suggestion.startsWith('New')).toBe(true);
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
test('Dictionary: Word removal and updates', () => {
|
|
975
|
+
const dictionary = new Trie<string>();
|
|
976
|
+
|
|
977
|
+
// Add initial words
|
|
978
|
+
dictionary.add('delete');
|
|
979
|
+
dictionary.add('deletion');
|
|
980
|
+
dictionary.add('deleted');
|
|
981
|
+
|
|
982
|
+
// Verify initial state
|
|
983
|
+
expect(dictionary.has('delete')).toBe(true);
|
|
984
|
+
expect(dictionary.size).toBe(3);
|
|
985
|
+
|
|
986
|
+
// Remove a word
|
|
987
|
+
const deleted = dictionary.delete('delete');
|
|
988
|
+
expect(deleted).toBe(true);
|
|
989
|
+
expect(dictionary.has('delete')).toBe(false);
|
|
990
|
+
expect(dictionary.has('deletion')).toBe(true);
|
|
991
|
+
expect(dictionary.has('deleted')).toBe(true);
|
|
992
|
+
expect(dictionary.size).toBe(2);
|
|
993
|
+
|
|
994
|
+
// Try to remove non-existent word
|
|
995
|
+
expect(dictionary.delete('notexist')).toBe(false);
|
|
996
|
+
});
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
describe('classic use', () => {
|
|
1000
|
+
test('@example Autocomplete: Prefix validation and checking', () => {
|
|
1001
|
+
const autocomplete = new Trie<string>(['gmail.com', 'gmail.co.nz', 'gmail.co.jp', 'yahoo.com', 'outlook.com']);
|
|
1002
|
+
|
|
1003
|
+
// Get all completions for a prefix
|
|
1004
|
+
const gmailCompletions = autocomplete.getWords('gmail');
|
|
1005
|
+
expect(gmailCompletions).toEqual(['gmail.com', 'gmail.co.nz', 'gmail.co.jp']);
|
|
1006
|
+
});
|
|
1007
|
+
|
|
1008
|
+
test('@example File System Path Operations', () => {
|
|
1009
|
+
const fileSystem = new Trie<string>([
|
|
1010
|
+
'/home/user/documents/file1.txt',
|
|
1011
|
+
'/home/user/documents/file2.txt',
|
|
1012
|
+
'/home/user/pictures/photo.jpg',
|
|
1013
|
+
'/home/user/pictures/vacation/',
|
|
1014
|
+
'/home/user/downloads'
|
|
1015
|
+
]);
|
|
1016
|
+
|
|
1017
|
+
// Find common directory prefix
|
|
1018
|
+
expect(fileSystem.getLongestCommonPrefix()).toBe('/home/user/');
|
|
1019
|
+
|
|
1020
|
+
// List all files in a directory
|
|
1021
|
+
const documentsFiles = fileSystem.getWords('/home/user/documents/');
|
|
1022
|
+
expect(documentsFiles).toEqual(['/home/user/documents/file1.txt', '/home/user/documents/file2.txt']);
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
test('@example Autocomplete: Basic word suggestions', () => {
|
|
1026
|
+
// Create a trie for autocomplete
|
|
1027
|
+
const autocomplete = new Trie<string>([
|
|
1028
|
+
'function',
|
|
1029
|
+
'functional',
|
|
1030
|
+
'functions',
|
|
1031
|
+
'class',
|
|
1032
|
+
'classes',
|
|
1033
|
+
'classical',
|
|
1034
|
+
'closure',
|
|
1035
|
+
'const',
|
|
1036
|
+
'constructor'
|
|
1037
|
+
]);
|
|
1038
|
+
|
|
1039
|
+
// Test autocomplete with different prefixes
|
|
1040
|
+
expect(autocomplete.getWords('fun')).toEqual(['functional', 'functions', 'function']);
|
|
1041
|
+
expect(autocomplete.getWords('cla')).toEqual(['classes', 'classical', 'class']);
|
|
1042
|
+
expect(autocomplete.getWords('con')).toEqual(['constructor', 'const']);
|
|
1043
|
+
|
|
1044
|
+
// Test with non-matching prefix
|
|
1045
|
+
expect(autocomplete.getWords('xyz')).toEqual([]);
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
test('@example Dictionary: Case-insensitive word lookup', () => {
|
|
1049
|
+
// Create a case-insensitive dictionary
|
|
1050
|
+
const dictionary = new Trie<string>([], { caseSensitive: false });
|
|
1051
|
+
|
|
1052
|
+
// Add words with mixed casing
|
|
1053
|
+
dictionary.add('Hello');
|
|
1054
|
+
dictionary.add('WORLD');
|
|
1055
|
+
dictionary.add('JavaScript');
|
|
1056
|
+
|
|
1057
|
+
// Test lookups with different casings
|
|
1058
|
+
expect(dictionary.has('hello')).toBe(true);
|
|
1059
|
+
expect(dictionary.has('HELLO')).toBe(true);
|
|
1060
|
+
expect(dictionary.has('Hello')).toBe(true);
|
|
1061
|
+
expect(dictionary.has('javascript')).toBe(true);
|
|
1062
|
+
expect(dictionary.has('JAVASCRIPT')).toBe(true);
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
test('@example IP Address Routing Table', () => {
|
|
1066
|
+
// Add IP address prefixes and their corresponding routes
|
|
1067
|
+
const routes = {
|
|
1068
|
+
'192.168.1': 'LAN_SUBNET_1',
|
|
1069
|
+
'192.168.2': 'LAN_SUBNET_2',
|
|
1070
|
+
'10.0.0': 'PRIVATE_NETWORK_1',
|
|
1071
|
+
'10.0.1': 'PRIVATE_NETWORK_2'
|
|
1072
|
+
};
|
|
1073
|
+
|
|
1074
|
+
const ipRoutingTable = new Trie<string>(Object.keys(routes));
|
|
1075
|
+
|
|
1076
|
+
// Check IP address prefix matching
|
|
1077
|
+
expect(ipRoutingTable.hasPrefix('192.168.1')).toBe(true);
|
|
1078
|
+
expect(ipRoutingTable.hasPrefix('192.168.2')).toBe(true);
|
|
1079
|
+
|
|
1080
|
+
// Validate IP address belongs to subnet
|
|
1081
|
+
const ip = '192.168.1.100';
|
|
1082
|
+
const subnet = ip.split('.').slice(0, 3).join('.');
|
|
1083
|
+
expect(ipRoutingTable.hasPrefix(subnet)).toBe(true);
|
|
1084
|
+
});
|
|
1085
|
+
});
|
|
@@ -16,9 +16,9 @@ describe('isComparable', () => {
|
|
|
16
16
|
expect(isComparable(-Infinity)).toBe(true);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('NaN should not be comparable', () => {
|
|
20
|
-
|
|
21
|
-
});
|
|
19
|
+
// it('NaN should not be comparable', () => {
|
|
20
|
+
// expect(isComparable(NaN)).toBe(false);
|
|
21
|
+
// });
|
|
22
22
|
|
|
23
23
|
it('strings should be comparable', () => {
|
|
24
24
|
expect(isComparable('hello')).toBe(true);
|
|
@@ -54,9 +54,9 @@ describe('isComparable', () => {
|
|
|
54
54
|
expect(isComparable(new Date('2024-01-01'))).toBe(true);
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
-
it('invalid Date objects should not be comparable', () => {
|
|
58
|
-
|
|
59
|
-
});
|
|
57
|
+
// it('invalid Date objects should not be comparable', () => {
|
|
58
|
+
// expect(isComparable(new Date('invalid'))).toBe(false);
|
|
59
|
+
// });
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
describe('arrays', () => {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DFSOperation = void 0;
|
|
4
|
-
var DFSOperation;
|
|
5
|
-
(function (DFSOperation) {
|
|
6
|
-
DFSOperation[DFSOperation["VISIT"] = 0] = "VISIT";
|
|
7
|
-
DFSOperation[DFSOperation["PROCESS"] = 1] = "PROCESS";
|
|
8
|
-
})(DFSOperation || (exports.DFSOperation = DFSOperation = {}));
|
|
9
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":";;;AAAA,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,iDAAS,CAAA;IACT,qDAAW,CAAA;AACb,CAAC,EAHW,YAAY,4BAAZ,YAAY,QAGvB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/constants/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,iDAAS,CAAA;IACT,qDAAW,CAAA;AACb,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB"}
|
package/src/constants/index.ts
DELETED
package/testToExample.ts
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import * as ts from 'typescript';
|
|
4
|
-
import { toPascalCase } from './test/utils';
|
|
5
|
-
|
|
6
|
-
const isReplaceMD = false;
|
|
7
|
-
const START_MARKER = '[//]: # (No deletion!!! Start of Example Replace Section)';
|
|
8
|
-
const END_MARKER = '[//]: # (No deletion!!! End of Example Replace Section)';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Recursively retrieve all `.ts` files in a directory.
|
|
12
|
-
*/
|
|
13
|
-
function getAllTestFiles(dir: string): string[] {
|
|
14
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
15
|
-
|
|
16
|
-
const files = entries
|
|
17
|
-
.filter(file => !file.isDirectory() && file.name.endsWith('.ts'))
|
|
18
|
-
.map(file => path.join(dir, file.name));
|
|
19
|
-
|
|
20
|
-
const directories = entries.filter(entry => entry.isDirectory());
|
|
21
|
-
|
|
22
|
-
for (const directory of directories) {
|
|
23
|
-
files.push(...getAllTestFiles(path.join(dir, directory.name)));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return files;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Extract test cases with `@example` from TypeScript files using AST.
|
|
31
|
-
*/
|
|
32
|
-
function extractExamplesFromFile(filePath: string): { name: string; body: string }[] {
|
|
33
|
-
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
34
|
-
const sourceFile = ts.createSourceFile(filePath, fileContent, ts.ScriptTarget.Latest, true);
|
|
35
|
-
|
|
36
|
-
const examples: { name: string; body: string }[] = [];
|
|
37
|
-
|
|
38
|
-
function visit(node: ts.Node) {
|
|
39
|
-
if (
|
|
40
|
-
ts.isCallExpression(node) && // Ensure it's a function call
|
|
41
|
-
node.arguments.length >= 2 && // At least two arguments
|
|
42
|
-
ts.isStringLiteral(node.arguments[0]) && // First argument is a string
|
|
43
|
-
node.arguments[0].text.startsWith('@example') && // Matches @example
|
|
44
|
-
ts.isArrowFunction(node.arguments[1]) // Second argument is an arrow function
|
|
45
|
-
) {
|
|
46
|
-
const exampleName = node.arguments[0].text.replace('@example ', '').trim();
|
|
47
|
-
const bodyNode = node.arguments[1].body;
|
|
48
|
-
|
|
49
|
-
let exampleBody: string;
|
|
50
|
-
if (ts.isBlock(bodyNode)) {
|
|
51
|
-
// If it's a block, remove outer {}
|
|
52
|
-
exampleBody = bodyNode.statements
|
|
53
|
-
.map(stmt => stmt.getFullText(sourceFile))
|
|
54
|
-
.join('')
|
|
55
|
-
.trim();
|
|
56
|
-
} else {
|
|
57
|
-
// If it's a single expression, use it directly
|
|
58
|
-
exampleBody = bodyNode.getFullText(sourceFile).trim();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const transformedBody = exampleBody
|
|
62
|
-
.replace(
|
|
63
|
-
/expect\((.*?)\)\.(toBeUndefined|toBeNull)\(\);/g,
|
|
64
|
-
(match, actual, method) => {
|
|
65
|
-
const expectedValue = method === 'toBeUndefined' ? 'undefined' : 'null';
|
|
66
|
-
return `console.log(${actual}); // ${expectedValue}`;
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
.replace(
|
|
70
|
-
/expect\((.*?)\)\.(toEqual|toBe|toStrictEqual|toHaveLength|toMatchObject)\((.*?)\);/gs, // Use `s` flag for multiline
|
|
71
|
-
(match, actual, method, expected) => {
|
|
72
|
-
expected = expected.replace(/\n/g, '\n //')
|
|
73
|
-
return `console.log(${actual}); // ${expected}`;
|
|
74
|
-
}
|
|
75
|
-
)
|
|
76
|
-
.trim();
|
|
77
|
-
|
|
78
|
-
examples.push({ name: exampleName, body: transformedBody });
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
ts.forEachChild(node, visit);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
visit(sourceFile);
|
|
85
|
-
|
|
86
|
-
return examples;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Add examples to the corresponding class in the source file.
|
|
91
|
-
*/
|
|
92
|
-
function addExamplesToSourceFile(
|
|
93
|
-
sourceFilePath: string,
|
|
94
|
-
className: string,
|
|
95
|
-
examples: { name: string; body: string }[]
|
|
96
|
-
): void {
|
|
97
|
-
if (!fs.existsSync(sourceFilePath)) {
|
|
98
|
-
console.warn(`Source file not found: ${sourceFilePath}`);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const sourceContent = fs.readFileSync(sourceFilePath, 'utf-8');
|
|
103
|
-
const sourceFile = ts.createSourceFile(sourceFilePath, sourceContent, ts.ScriptTarget.Latest, true);
|
|
104
|
-
|
|
105
|
-
let updatedContent = sourceContent;
|
|
106
|
-
|
|
107
|
-
const classNode = sourceFile.statements.find(
|
|
108
|
-
stmt => ts.isClassDeclaration(stmt) && stmt.name?.text === className
|
|
109
|
-
) as ts.ClassDeclaration | undefined;
|
|
110
|
-
|
|
111
|
-
if (classNode) {
|
|
112
|
-
const classStart = classNode.getStart(sourceFile);
|
|
113
|
-
const classEnd = classNode.getEnd();
|
|
114
|
-
const classText = classNode.getFullText(sourceFile);
|
|
115
|
-
|
|
116
|
-
// Extract annotation content
|
|
117
|
-
const existingCommentMatch = classText.match(/\/\*\*([\s\S]*?)\*\//);
|
|
118
|
-
if (!existingCommentMatch) {
|
|
119
|
-
console.warn(`No existing comment found for class: ${className}`);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const existingCommentInner = existingCommentMatch[1].replace(/^\n \* /, ''); // Extract comment content (excluding `/**` and `*/`)
|
|
124
|
-
|
|
125
|
-
// Replace @example part
|
|
126
|
-
const exampleSection = examples
|
|
127
|
-
.map(
|
|
128
|
-
example =>
|
|
129
|
-
` * @example \n * \/\/ ${example.name} \n${example.body
|
|
130
|
-
.split('\n')
|
|
131
|
-
.map(line => ` * ${line}`)
|
|
132
|
-
.join('\n')}`
|
|
133
|
-
)
|
|
134
|
-
.join('\n') + '\n ';
|
|
135
|
-
|
|
136
|
-
let newComment = '';
|
|
137
|
-
if (existingCommentInner.includes('@example')) {
|
|
138
|
-
newComment = existingCommentInner.replace(/ \* @example[\s\S]*?(?=\*\/|$)/g, exampleSection);
|
|
139
|
-
} else {
|
|
140
|
-
newComment = existingCommentInner + `${exampleSection}`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
// Replace original content
|
|
145
|
-
updatedContent =
|
|
146
|
-
sourceContent.slice(0, classStart - existingCommentInner.length - 3) +
|
|
147
|
-
newComment +
|
|
148
|
-
classText.slice(existingCommentMatch[0].length).trim() +
|
|
149
|
-
sourceContent.slice(classEnd);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
fs.writeFileSync(sourceFilePath, updatedContent, 'utf-8');
|
|
153
|
-
console.log(`Updated examples in ${sourceFilePath}`);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Process all test files and update README.md and source files.
|
|
159
|
-
*/
|
|
160
|
-
function updateExamples(testDir: string, readmePath: string, sourceBaseDir: string): void {
|
|
161
|
-
const testFiles = getAllTestFiles(testDir);
|
|
162
|
-
|
|
163
|
-
let allExamples: string[] = [];
|
|
164
|
-
for (const file of testFiles) {
|
|
165
|
-
const examples = extractExamplesFromFile(file);
|
|
166
|
-
|
|
167
|
-
if (examples.length === 0) {
|
|
168
|
-
console.log(`No @example found in test file: ${file}`);
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const relativePath = path.relative(testDir, file);
|
|
173
|
-
const sourceFilePath = path.resolve(sourceBaseDir, relativePath.replace('.test.ts', '.ts'));
|
|
174
|
-
const className = path.basename(sourceFilePath, '.ts');
|
|
175
|
-
|
|
176
|
-
addExamplesToSourceFile(sourceFilePath, toPascalCase(className), examples);
|
|
177
|
-
|
|
178
|
-
allExamples = allExamples.concat(
|
|
179
|
-
examples.map(example => `### ${example.name}\n\`\`\`typescript\n${example.body}\n\`\`\``)
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (isReplaceMD && allExamples.length > 0) {
|
|
184
|
-
replaceExamplesInReadme(readmePath, allExamples);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Replace content between markers in README.md.
|
|
190
|
-
*/
|
|
191
|
-
function replaceExamplesInReadme(readmePath: string, newExamples: string[]): void {
|
|
192
|
-
const readmeContent = fs.readFileSync(readmePath, 'utf-8');
|
|
193
|
-
|
|
194
|
-
const startIdx = readmeContent.indexOf(START_MARKER);
|
|
195
|
-
const endIdx = readmeContent.indexOf(END_MARKER);
|
|
196
|
-
|
|
197
|
-
if (startIdx === -1 || endIdx === -1) {
|
|
198
|
-
throw new Error(`Markers not found in ${readmePath}`);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const before = readmeContent.slice(0, startIdx + START_MARKER.length);
|
|
202
|
-
const after = readmeContent.slice(endIdx);
|
|
203
|
-
|
|
204
|
-
const updatedContent = `${before}\n\n${newExamples.join('\n\n')}\n\n${after}`;
|
|
205
|
-
fs.writeFileSync(readmePath, updatedContent, 'utf-8');
|
|
206
|
-
|
|
207
|
-
console.log(`README.md updated with new examples.`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Run the script
|
|
211
|
-
const testDir = path.resolve(__dirname, 'test/unit');
|
|
212
|
-
const readmePath = path.resolve(__dirname, 'README.md');
|
|
213
|
-
const sourceBaseDir = path.resolve(__dirname, 'src');
|
|
214
|
-
|
|
215
|
-
updateExamples(testDir, readmePath, sourceBaseDir);
|