hybridtm 0.4.0 → 0.5.0

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 (107) hide show
  1. package/package.json +9 -8
  2. package/dist/batchimporter.d.ts +0 -22
  3. package/dist/batchimporter.js +0 -203
  4. package/dist/constants.d.ts +0 -15
  5. package/dist/constants.js +0 -16
  6. package/dist/constants.js.map +0 -1
  7. package/dist/debug-progress.d.ts +0 -12
  8. package/dist/debug-progress.js +0 -49
  9. package/dist/debug-progress.js.map +0 -1
  10. package/dist/ngramIndex.d.ts +0 -31
  11. package/dist/ngramIndex.js +0 -132
  12. package/dist/ngramIndex.js.map +0 -1
  13. package/dist/ngrams.d.ts +0 -21
  14. package/dist/ngrams.js +0 -73
  15. package/dist/ngrams.js.map +0 -1
  16. package/dist/package.json +0 -35
  17. package/dist/progressProvider.d.ts +0 -17
  18. package/dist/progressProvider.js +0 -14
  19. package/dist/progressProvider.js.map +0 -1
  20. package/dist/simplexlifftest.d.ts +0 -1
  21. package/dist/simplexlifftest.js +0 -23
  22. package/dist/simplexlifftest.js.map +0 -1
  23. package/dist/test-import.d.ts +0 -12
  24. package/dist/test-import.js +0 -101
  25. package/dist/test-import.js.map +0 -1
  26. package/dist/test-progress-fix.d.ts +0 -1
  27. package/dist/test-progress-fix.js +0 -32
  28. package/dist/test-progress-fix.js.map +0 -1
  29. package/dist/test-progress.d.ts +0 -12
  30. package/dist/test-progress.js +0 -32
  31. package/dist/test-progress.js.map +0 -1
  32. package/dist/tests/vectorSimilarityComparison.d.ts +0 -12
  33. package/dist/tests/vectorSimilarityComparison.js +0 -153
  34. package/dist/tests/vectorSimilarityComparison.js.map +0 -1
  35. package/dist/tmxreader.d.ts +0 -25
  36. package/dist/tmxreader.js +0 -51
  37. package/dist/tmxtest.d.ts +0 -16
  38. package/dist/tmxtest.js +0 -316
  39. package/dist/tmxtest.js.map +0 -1
  40. package/dist/ts/batchImporter.js.map +0 -1
  41. package/dist/ts/hybridtm.d.ts +0 -67
  42. package/dist/ts/hybridtm.js +0 -932
  43. package/dist/ts/hybridtm.js.map +0 -1
  44. package/dist/ts/hybridtmFactory.d.ts +0 -43
  45. package/dist/ts/hybridtmFactory.js +0 -165
  46. package/dist/ts/hybridtmFactory.js.map +0 -1
  47. package/dist/ts/importOptions.d.ts +0 -21
  48. package/dist/ts/importOptions.js +0 -24
  49. package/dist/ts/importOptions.js.map +0 -1
  50. package/dist/ts/index.d.ts +0 -25
  51. package/dist/ts/index.js +0 -22
  52. package/dist/ts/index.js.map +0 -1
  53. package/dist/ts/langEntry.d.ts +0 -64
  54. package/dist/ts/langEntry.js +0 -13
  55. package/dist/ts/langEntry.js.map +0 -1
  56. package/dist/ts/match.d.ts +0 -22
  57. package/dist/ts/match.js +0 -38
  58. package/dist/ts/match.js.map +0 -1
  59. package/dist/ts/matchQuality.d.ts +0 -16
  60. package/dist/ts/matchQuality.js +0 -83
  61. package/dist/ts/matchQuality.js.map +0 -1
  62. package/dist/ts/pendingEntry.d.ts +0 -24
  63. package/dist/ts/pendingEntry.js +0 -13
  64. package/dist/ts/pendingEntry.js.map +0 -1
  65. package/dist/ts/searchFilters.d.ts +0 -24
  66. package/dist/ts/searchFilters.js +0 -13
  67. package/dist/ts/searchFilters.js.map +0 -1
  68. package/dist/ts/tmxHandler.d.ts +0 -61
  69. package/dist/ts/tmxHandler.js +0 -347
  70. package/dist/ts/tmxHandler.js.map +0 -1
  71. package/dist/ts/tmxReader.js.map +0 -1
  72. package/dist/ts/tmxtest.d.ts +0 -16
  73. package/dist/ts/tmxtest.js +0 -316
  74. package/dist/ts/tmxtest.js.map +0 -1
  75. package/dist/ts/utils.d.ts +0 -17
  76. package/dist/ts/utils.js +0 -49
  77. package/dist/ts/utils.js.map +0 -1
  78. package/dist/ts/xliffHandler.d.ts +0 -67
  79. package/dist/ts/xliffHandler.js +0 -522
  80. package/dist/ts/xliffHandler.js.map +0 -1
  81. package/dist/ts/xliffReader.js.map +0 -1
  82. package/dist/ts/xlifftest.d.ts +0 -54
  83. package/dist/ts/xlifftest.js +0 -245
  84. package/dist/ts/xlifftest.js.map +0 -1
  85. package/dist/vectorSimilarityTester.d.ts +0 -56
  86. package/dist/vectorSimilarityTester.js +0 -164
  87. package/dist/vectorSimilarityTester.js.map +0 -1
  88. package/dist/xliffreader.d.ts +0 -25
  89. package/dist/xliffreader.js +0 -50
  90. package/dist/xlifftest.d.ts +0 -54
  91. package/dist/xlifftest.js +0 -245
  92. package/dist/xlifftest.js.map +0 -1
  93. /package/dist/{ts/batchImporter.d.ts → batchImporter.d.ts} +0 -0
  94. /package/dist/{ts/batchImporter.js → batchImporter.js} +0 -0
  95. /package/dist/{batchimporter.js.map → batchImporter.js.map} +0 -0
  96. /package/dist/{tmxhandler.d.ts → tmxHandler.d.ts} +0 -0
  97. /package/dist/{tmxhandler.js → tmxHandler.js} +0 -0
  98. /package/dist/{tmxhandler.js.map → tmxHandler.js.map} +0 -0
  99. /package/dist/{ts/tmxReader.d.ts → tmxReader.d.ts} +0 -0
  100. /package/dist/{ts/tmxReader.js → tmxReader.js} +0 -0
  101. /package/dist/{tmxreader.js.map → tmxReader.js.map} +0 -0
  102. /package/dist/{xliffhandler.d.ts → xliffHandler.d.ts} +0 -0
  103. /package/dist/{xliffhandler.js → xliffHandler.js} +0 -0
  104. /package/dist/{xliffhandler.js.map → xliffHandler.js.map} +0 -0
  105. /package/dist/{ts/xliffReader.d.ts → xliffReader.d.ts} +0 -0
  106. /package/dist/{ts/xliffReader.js → xliffReader.js} +0 -0
  107. /package/dist/{xliffreader.js.map → xliffReader.js.map} +0 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hybridtm",
3
3
  "productName": "HybridTM",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "description": "HybridTM is a Translation Memory (TM) engine that combines semantic embeddings with fuzzy string matching.",
6
6
  "main": "dist/index.js",
7
7
  "type": "module",
@@ -10,7 +10,8 @@
10
10
  "/dist"
11
11
  ],
12
12
  "scripts": {
13
- "build": "tsc"
13
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
14
+ "build": "npm run clean && tsc"
14
15
  },
15
16
  "author": {
16
17
  "name": "Rodolfo M. Raya",
@@ -27,12 +28,12 @@
27
28
  "@lancedb/lancedb": "^0.27.2",
28
29
  "@xenova/transformers": "^2.17.2",
29
30
  "apache-arrow": "^18.1.0",
30
- "sdltm": "^2.2.0",
31
- "typesbcp47": "^1.21.0",
32
- "typesxml": "^2.0.0"
31
+ "sdltm": "^2.5.0",
32
+ "typesbcp47": "^1.24.0",
33
+ "typesxml": "^2.2.0"
33
34
  },
34
35
  "devDependencies": {
35
- "@types/node": "^24.12.2",
36
- "typescript": "^6.0.2"
36
+ "@types/node": "^24.13.0",
37
+ "typescript": "^6.0.3"
37
38
  }
38
- }
39
+ }
@@ -1,22 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025-2026 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- import { HybridTM } from './hybridtm.js';
13
- export declare class BatchImporter {
14
- private tm;
15
- private tempFilePath;
16
- private batchSize;
17
- private totalEntries;
18
- constructor(tm: HybridTM, tempFilePath: string, totalEntries?: number, batchSize?: number);
19
- import(): Promise<void>;
20
- private parseMetadata;
21
- private cleanup;
22
- }
@@ -1,203 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025-2026 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- import { createReadStream, existsSync, unlinkSync } from "node:fs";
13
- import { createInterface } from 'node:readline';
14
- import { Utils } from './utils.js';
15
- export class BatchImporter {
16
- tm;
17
- tempFilePath;
18
- batchSize;
19
- totalEntries;
20
- constructor(tm, tempFilePath, totalEntries = 0, batchSize = 1000) {
21
- this.tm = tm;
22
- this.tempFilePath = tempFilePath;
23
- this.totalEntries = totalEntries;
24
- this.batchSize = batchSize;
25
- }
26
- async import() {
27
- try {
28
- console.log('Starting batch import from ' + this.tempFilePath + '...');
29
- if (this.totalEntries > 0) {
30
- console.log('Total entries to import: ' + this.totalEntries.toLocaleString());
31
- }
32
- const fileStream = createReadStream(this.tempFilePath, { encoding: 'utf8' });
33
- const rl = createInterface({
34
- input: fileStream,
35
- crlfDelay: Infinity
36
- });
37
- let batch = [];
38
- let totalProcessed = 0;
39
- let batchCount = 0;
40
- const startTime = Date.now();
41
- for await (const line of rl) {
42
- if (!line.trim()) {
43
- continue; // Skip empty lines
44
- }
45
- try {
46
- const jsonEntry = JSON.parse(line);
47
- const segmentIndex = typeof jsonEntry.segmentIndex === 'number' ? jsonEntry.segmentIndex : 0;
48
- const segmentCount = typeof jsonEntry.segmentCount === 'number' ? jsonEntry.segmentCount : 1;
49
- const metadata = this.parseMetadata(jsonEntry.metadata);
50
- // Convert JSON entry to PendingEntry
51
- const entry = {
52
- language: jsonEntry.language,
53
- fileId: jsonEntry.fileId,
54
- original: jsonEntry.original,
55
- unitId: jsonEntry.unitId,
56
- pureText: jsonEntry.pureText,
57
- element: Utils.buildXMLElement(jsonEntry.element),
58
- segmentIndex,
59
- segmentCount,
60
- metadata
61
- };
62
- batch.push(entry);
63
- // Process batch when it reaches the batch size
64
- if (batch.length >= this.batchSize) {
65
- batchCount++;
66
- await this.tm.storeBatchEntries(batch);
67
- totalProcessed += batch.length;
68
- // Calculate progress and ETA
69
- const elapsed = Date.now() - startTime;
70
- const rate = totalProcessed / (elapsed / 1000); // entries per second
71
- if (this.totalEntries > 0) {
72
- const progress = (totalProcessed / this.totalEntries) * 100;
73
- const remaining = this.totalEntries - totalProcessed;
74
- const etaSeconds = remaining / rate;
75
- const etaMinutes = Math.floor(etaSeconds / 60);
76
- const etaSecondsRemainder = Math.floor(etaSeconds % 60);
77
- console.log('Progress: ' + totalProcessed.toLocaleString() + '/' + this.totalEntries.toLocaleString() + ' (' + progress.toFixed(1) + '%) - ETA: ' + etaMinutes + 'm ' + etaSecondsRemainder + 's - ' + rate.toFixed(1) + ' entries/sec');
78
- }
79
- else {
80
- console.log('Processed: ' + totalProcessed.toLocaleString() + ' entries - ' + rate.toFixed(1) + ' entries/sec');
81
- }
82
- batch = [];
83
- }
84
- }
85
- catch (parseErr) {
86
- console.error('Error parsing JSONL line: ' + parseErr);
87
- // Continue with next line
88
- }
89
- }
90
- // Process any remaining entries in the final batch
91
- if (batch.length > 0) {
92
- batchCount++;
93
- await this.tm.storeBatchEntries(batch);
94
- totalProcessed += batch.length;
95
- }
96
- const totalTime = (Date.now() - startTime) / 1000;
97
- const minutes = Math.floor(totalTime / 60);
98
- const seconds = Math.floor(totalTime % 60);
99
- const avgRate = totalProcessed / totalTime;
100
- console.log('\nBatch import complete!');
101
- console.log('Total entries imported: ' + totalProcessed.toLocaleString());
102
- console.log('Total time: ' + minutes + 'm ' + seconds + 's');
103
- console.log('Average rate: ' + avgRate.toFixed(1) + ' entries/sec');
104
- // Clean up the temporary file
105
- await this.cleanup();
106
- }
107
- catch (err) {
108
- console.error('Error during batch import:', err);
109
- throw err;
110
- }
111
- }
112
- parseMetadata(metadata) {
113
- if (!metadata || typeof metadata !== 'object') {
114
- return {};
115
- }
116
- const result = {};
117
- const source = metadata;
118
- const copyString = (key) => {
119
- const value = source[key];
120
- if (typeof value === 'string' && value.length > 0) {
121
- result[key] = value;
122
- }
123
- };
124
- const copyNumber = (key) => {
125
- const value = source[key];
126
- if (typeof value === 'number' && !Number.isNaN(value)) {
127
- result[key] = value;
128
- }
129
- };
130
- copyString('state');
131
- copyString('subState');
132
- copyNumber('quality');
133
- copyString('creationDate');
134
- copyString('creationId');
135
- copyString('changeDate');
136
- copyString('changeId');
137
- copyString('creationTool');
138
- copyString('creationToolVersion');
139
- copyString('context');
140
- copyNumber('usageCount');
141
- copyString('lastUsageDate');
142
- const notes = source.notes;
143
- if (Array.isArray(notes)) {
144
- const filtered = notes.filter((item) => typeof item === 'string' && item.length > 0);
145
- if (filtered.length > 0) {
146
- result.notes = filtered;
147
- }
148
- }
149
- const properties = source.properties;
150
- if (properties && typeof properties === 'object') {
151
- const props = {};
152
- Object.entries(properties).forEach(([key, value]) => {
153
- if (typeof value === 'string') {
154
- props[key] = value;
155
- }
156
- });
157
- if (Object.keys(props).length > 0) {
158
- result.properties = props;
159
- }
160
- }
161
- const segment = source.segment;
162
- if (segment && typeof segment === 'object') {
163
- const segmentSource = segment;
164
- const segmentMetadata = {};
165
- const copySegmentString = (key) => {
166
- const value = segmentSource[key];
167
- if (typeof value === 'string' && value.length > 0) {
168
- segmentMetadata[key] = value;
169
- }
170
- };
171
- const copySegmentNumber = (key) => {
172
- const value = segmentSource[key];
173
- if (typeof value === 'number' && !Number.isNaN(value)) {
174
- segmentMetadata[key] = value;
175
- }
176
- };
177
- copySegmentString('provider');
178
- copySegmentString('fileHash');
179
- copySegmentString('fileId');
180
- copySegmentString('unitId');
181
- copySegmentString('segmentId');
182
- copySegmentString('segmentKey');
183
- copySegmentNumber('segmentIndex');
184
- copySegmentNumber('segmentCount');
185
- if (Object.keys(segmentMetadata).length > 0) {
186
- result.segment = segmentMetadata;
187
- }
188
- }
189
- return Object.keys(result).length > 0 ? result : {};
190
- }
191
- async cleanup() {
192
- try {
193
- if (existsSync(this.tempFilePath)) {
194
- unlinkSync(this.tempFilePath);
195
- }
196
- }
197
- catch (err) {
198
- console.error('Error cleaning up temporary file ' + this.tempFilePath + ':', err);
199
- // Don't throw - cleanup failure shouldn't fail the import
200
- }
201
- }
202
- }
203
- //# sourceMappingURL=batchImporter.js.map
@@ -1,15 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025-2026 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- export declare class Constants {
13
- static readonly VERSION: string;
14
- static readonly BUILD: string;
15
- }
package/dist/constants.js DELETED
@@ -1,16 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025-2026 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- export class Constants {
13
- static VERSION = "1.0.0";
14
- static BUILD = "20260104_0539";
15
- }
16
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../ts/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;iFAUiF;AAEjF,MAAM,OAAO,SAAS;IACX,MAAM,CAAU,OAAO,GAAW,OAAO,CAAC;IAC1C,MAAM,CAAU,KAAK,GAAW,eAAe,CAAC"}
@@ -1,12 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse Public License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- export {};
@@ -1,49 +0,0 @@
1
- "use strict";
2
- /*******************************************************************************
3
- * Copyright (c) 2025 Maxprograms.
4
- *
5
- * This program and the accompanying materials
6
- * are made available under the terms of the Eclipse Public License 1.0
7
- * which accompanies this distribution, and is available at
8
- * https://www.eclipse.org/org/documents/epl-v10.html
9
- *
10
- * Contributors:
11
- * Maxprograms - initial API and implementation
12
- *******************************************************************************/
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- const hybridtm_1 = require("./hybridtm");
15
- async function debugProgress() {
16
- console.log('Debugging progress tracking during actual TMX import...\n');
17
- const tm = new hybridtm_1.HybridTM('/tmp/debug-progress.lancedb', hybridtm_1.HybridTM.SPEED_MODEL);
18
- // Start progress monitoring with debugging
19
- let pollCount = 0;
20
- const progressInterval = setInterval(() => {
21
- const progress = tm.getImportProgress();
22
- pollCount++;
23
- console.log(`Poll ${pollCount}: processed=${progress.entriesProcessed}, pending=${progress.entriesPending}, importing=${progress.isImporting}, fileName='${progress.fileName}'`);
24
- if (!progress.isImporting && pollCount > 5) {
25
- console.log('Import appears to have finished');
26
- clearInterval(progressInterval);
27
- }
28
- }, 1000); // Check every 1 second for debugging
29
- try {
30
- console.log('Starting TMX import...');
31
- await tm.importTMX('/Users/rmraya/Desktop/Norden/NordenTM_2023_rev2.tmx');
32
- console.log('TMX import completed');
33
- }
34
- catch (error) {
35
- console.error('Import failed:', error);
36
- }
37
- finally {
38
- clearInterval(progressInterval);
39
- }
40
- const finalProgress = tm.getImportProgress();
41
- console.log(`Final: processed=${finalProgress.entriesProcessed}, pending=${finalProgress.entriesPending}`);
42
- await tm.close();
43
- console.log('✓ Progress debug completed');
44
- }
45
- debugProgress().catch(error => {
46
- console.error('Debug failed:', error);
47
- process.exit(1);
48
- });
49
- //# sourceMappingURL=debug-progress.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug-progress.js","sourceRoot":"","sources":["../ts/debug-progress.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;iFAUiF;;AAEjF,yCAAsC;AAEtC,KAAK,UAAU,aAAa;IACxB,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IAEzE,MAAM,EAAE,GAAG,IAAI,mBAAQ,CAAC,6BAA6B,EAAE,mBAAQ,CAAC,WAAW,CAAC,CAAC;IAE7E,2CAA2C;IAC3C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,MAAM,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE;QACtC,MAAM,QAAQ,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;QACxC,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,QAAQ,SAAS,eAAe,QAAQ,CAAC,gBAAgB,aAAa,QAAQ,CAAC,cAAc,eAAe,QAAQ,CAAC,WAAW,eAAe,QAAQ,CAAC,QAAQ,GAAG,CAAC,CAAC;QAEjL,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;YAC/C,aAAa,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,qCAAqC;IAE/C,IAAI,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,MAAM,EAAE,CAAC,SAAS,CAAC,qDAAqD,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;YAAS,CAAC;QACP,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,aAAa,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,oBAAoB,aAAa,CAAC,gBAAgB,aAAa,aAAa,CAAC,cAAc,EAAE,CAAC,CAAC;IAE3G,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAC9C,CAAC;AAED,aAAa,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;IAC1B,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
@@ -1,31 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- import { Connection } from "@lancedb/lancedb";
13
- interface NGramUpsert {
14
- language: string;
15
- entryId: string;
16
- ngrams: number[];
17
- }
18
- export declare class NGramIndex {
19
- private readonly db;
20
- private static readonly TABLE_NAME;
21
- private table;
22
- private initializing;
23
- constructor(db: Connection);
24
- initialize(): Promise<void>;
25
- upsert(entries: NGramUpsert[]): Promise<void>;
26
- remove(entryId: string): Promise<void>;
27
- collect(language: string, ngrams: number[]): Promise<Map<string, number>>;
28
- private ensureTable;
29
- private deleteByEntryIds;
30
- }
31
- export {};
@@ -1,132 +0,0 @@
1
- "use strict";
2
- /*******************************************************************************
3
- * Copyright (c) 2025 Maxprograms.
4
- *
5
- * This program and the accompanying materials
6
- * are made available under the terms of the Eclipse License 1.0
7
- * which accompanies this distribution, and is available at
8
- * https://www.eclipse.org/org/documents/epl-v10.html
9
- *
10
- * Contributors:
11
- * Maxprograms - initial API and implementation
12
- *******************************************************************************/
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.NGramIndex = void 0;
15
- const apache_arrow_1 = require("apache-arrow");
16
- const utils_1 = require("./utils");
17
- class NGramIndex {
18
- db;
19
- static TABLE_NAME = "ngramIndex";
20
- table = null;
21
- initializing = null;
22
- constructor(db) {
23
- this.db = db;
24
- // Expect external initialization
25
- }
26
- async initialize() {
27
- if (this.initializing) {
28
- await this.initializing;
29
- return;
30
- }
31
- this.initializing = this.ensureTable();
32
- try {
33
- await this.initializing;
34
- }
35
- finally {
36
- this.initializing = null;
37
- }
38
- }
39
- async upsert(entries) {
40
- if (!entries || entries.length === 0) {
41
- return;
42
- }
43
- const table = await this.ensureTable();
44
- const uniqueIds = new Set();
45
- const rows = [];
46
- for (const entry of entries) {
47
- uniqueIds.add(entry.entryId);
48
- const uniqueNgrams = Array.from(new Set(entry.ngrams));
49
- for (const ngram of uniqueNgrams) {
50
- rows.push({
51
- ngram: ngram,
52
- language: entry.language,
53
- entryid: entry.entryId
54
- });
55
- }
56
- }
57
- await this.deleteByEntryIds(Array.from(uniqueIds), table);
58
- if (rows.length > 0) {
59
- await table.add(rows);
60
- }
61
- }
62
- async remove(entryId) {
63
- if (!entryId) {
64
- return;
65
- }
66
- const table = await this.ensureTable();
67
- await table.delete("entryid = '" + utils_1.Utils.escapeSqlLiteral(entryId) + "'");
68
- }
69
- async collect(language, ngrams) {
70
- const result = new Map();
71
- if (!language || !ngrams || ngrams.length === 0) {
72
- return result;
73
- }
74
- const table = await this.ensureTable();
75
- const unique = Array.from(new Set(ngrams));
76
- const chunkSize = 512;
77
- for (let i = 0; i < unique.length; i += chunkSize) {
78
- const chunk = unique.slice(i, i + chunkSize);
79
- if (chunk.length === 0) {
80
- continue;
81
- }
82
- const ngramList = chunk.join(",");
83
- const filter = "language = '" + language + "' AND ngram IN (" + ngramList + ")";
84
- const rows = await table.query().where(filter).toArray();
85
- for (const row of rows) {
86
- const existing = result.get(row.entryid);
87
- if (typeof existing === "number") {
88
- result.set(row.entryid, existing + 1);
89
- }
90
- else {
91
- result.set(row.entryid, 1);
92
- }
93
- }
94
- }
95
- return result;
96
- }
97
- async ensureTable() {
98
- if (this.table) {
99
- return this.table;
100
- }
101
- const names = await this.db.tableNames();
102
- if (!names.includes(NGramIndex.TABLE_NAME)) {
103
- const schema = new apache_arrow_1.Schema([
104
- apache_arrow_1.Field.new("ngram", new apache_arrow_1.Int32(), false),
105
- apache_arrow_1.Field.new("language", new apache_arrow_1.Utf8(), false),
106
- apache_arrow_1.Field.new("entryid", new apache_arrow_1.Utf8(), false)
107
- ]);
108
- this.table = await this.db.createEmptyTable(NGramIndex.TABLE_NAME, schema);
109
- }
110
- else {
111
- this.table = await this.db.openTable(NGramIndex.TABLE_NAME);
112
- }
113
- return this.table;
114
- }
115
- async deleteByEntryIds(entryIds, table) {
116
- if (!entryIds || entryIds.length === 0) {
117
- return;
118
- }
119
- const target = table ? table : await this.ensureTable();
120
- const uniqueIds = Array.from(new Set(entryIds));
121
- const chunkSize = 256;
122
- for (let i = 0; i < uniqueIds.length; i += chunkSize) {
123
- const chunk = uniqueIds.slice(i, i + chunkSize).map(function (id) {
124
- return "'" + utils_1.Utils.escapeSqlLiteral(id) + "'";
125
- });
126
- const filter = "entryid IN (" + chunk.join(",") + ")";
127
- await target.delete(filter);
128
- }
129
- }
130
- }
131
- exports.NGramIndex = NGramIndex;
132
- //# sourceMappingURL=ngramIndex.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ngramIndex.js","sourceRoot":"","sources":["../ts/ngramIndex.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;iFAUiF;;;AAGjF,+CAA0D;AAC1D,mCAAgC;AAehC,MAAa,UAAU;IAOU;IALrB,MAAM,CAAU,UAAU,GAAW,YAAY,CAAC;IAElD,KAAK,GAAiB,IAAI,CAAC;IAC3B,YAAY,GAA0B,IAAI,CAAC;IAEnD,YAA6B,EAAc;QAAd,OAAE,GAAF,EAAE,CAAY;QACvC,iCAAiC;IACrC,CAAC;IAED,KAAK,CAAC,UAAU;QACZ,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,MAAM,IAAI,CAAC,YAAY,CAAC;YACxB,OAAO;QACX,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACvC,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,YAAY,CAAC;QAC5B,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC7B,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAsB;QAC/B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnC,OAAO;QACX,CAAC;QACD,MAAM,KAAK,GAAU,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,SAAS,GAAgB,IAAI,GAAG,EAAU,CAAC;QACjD,MAAM,IAAI,GAAoB,EAAE,CAAC;QAEjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7B,MAAM,YAAY,GAAa,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YACjE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBAC/B,IAAI,CAAC,IAAI,CAAC;oBACN,KAAK,EAAE,KAAK;oBACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;iBACzB,CAAC,CAAC;YACP,CAAC;QACL,CAAC;QAED,MAAM,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC,CAAC;QAE1D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QACxB,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,OAAO;QACX,CAAC;QACD,MAAM,KAAK,GAAU,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,KAAK,CAAC,MAAM,CAAC,aAAa,GAAG,aAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,QAAgB,EAAE,MAAgB;QAC5C,MAAM,MAAM,GAAwB,IAAI,GAAG,EAAkB,CAAC;QAC9D,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,MAAM,CAAC;QAClB,CAAC;QAED,MAAM,KAAK,GAAU,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAa,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,GAAW,GAAG,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YACxD,MAAM,KAAK,GAAa,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;YACvD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,SAAS;YACb,CAAC;YACD,MAAM,SAAS,GAAW,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,MAAM,GAAW,cAAc,GAAG,QAAQ,GAAG,kBAAkB,GAAG,SAAS,GAAG,GAAG,CAAC;YACxF,MAAM,IAAI,GAAoB,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,EAAqB,CAAC;YAC7F,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACrB,MAAM,QAAQ,GAAuB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC7D,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;oBAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;gBAC1C,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBAC/B,CAAC;YACL,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,WAAW;QACrB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,KAAK,CAAC;QACtB,CAAC;QACD,MAAM,KAAK,GAAa,MAAM,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACzC,MAAM,MAAM,GAAW,IAAI,qBAAM,CAAC;gBAC9B,oBAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,oBAAK,EAAE,EAAE,KAAK,CAAC;gBACtC,oBAAK,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,mBAAI,EAAE,EAAE,KAAK,CAAC;gBACxC,oBAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,mBAAI,EAAE,EAAE,KAAK,CAAC;aAC1C,CAAC,CAAC;YACH,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC/E,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,QAAkB,EAAE,KAAa;QAC5D,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrC,OAAO;QACX,CAAC;QACD,MAAM,MAAM,GAAU,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QAC/D,MAAM,SAAS,GAAa,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAW,GAAG,CAAC;QAE9B,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAa,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,UAAS,EAAU;gBAC7E,OAAO,GAAG,GAAG,aAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;YAClD,CAAC,CAAC,CAAC;YACH,MAAM,MAAM,GAAW,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YAC9D,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACL,CAAC;;AA3HL,gCA4HC"}
package/dist/ngrams.d.ts DELETED
@@ -1,21 +0,0 @@
1
- /*******************************************************************************
2
- * Copyright (c) 2025 Maxprograms.
3
- *
4
- * This program and the accompanying materials
5
- * are made available under the terms of the Eclipse License 1.0
6
- * which accompanies this distribution, and is available at
7
- * https://www.eclipse.org/org/documents/epl-v10.html
8
- *
9
- * Contributors:
10
- * Maxprograms - initial API and implementation
11
- *******************************************************************************/
12
- export declare class NGrams {
13
- private static readonly NGRAM_SIZE;
14
- static readonly SEPARATORS: string;
15
- static readonly TERM_SEPARATORS: string;
16
- private constructor();
17
- static getNGrams(source: string): number[];
18
- static buildWordList(source: string, separators: string): string[];
19
- private static escapeForRegex;
20
- private static javaHashCode;
21
- }
package/dist/ngrams.js DELETED
@@ -1,73 +0,0 @@
1
- "use strict";
2
- /*******************************************************************************
3
- * Copyright (c) 2025 Maxprograms.
4
- *
5
- * This program and the accompanying materials
6
- * are made available under the terms of the Eclipse License 1.0
7
- * which accompanies this distribution, and is available at
8
- * https://www.eclipse.org/org/documents/epl-v10.html
9
- *
10
- * Contributors:
11
- * Maxprograms - initial API and implementation
12
- *******************************************************************************/
13
- Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.NGrams = void 0;
15
- class NGrams {
16
- static NGRAM_SIZE = 3;
17
- static SEPARATORS = " \r\n\f\t\u2028\u2029,.;\":<>¿?¡!()[]{}=+-/*\u00AB\u00BB\u201C\u201D\u201E\uFF00";
18
- static TERM_SEPARATORS = " \u00A0\r\n\f\t\u2028\u2029,.;\":<>¿?¡!()[]{}=+/*\u00AB\u00BB\u201C\u201D\u201E\uFF00";
19
- constructor() {
20
- // Utility class
21
- }
22
- static getNGrams(source) {
23
- if (!source) {
24
- return [];
25
- }
26
- const src = source.toLowerCase();
27
- const words = NGrams.buildWordList(src, NGrams.SEPARATORS);
28
- const unique = new Set();
29
- for (const word of words) {
30
- if (!word) {
31
- continue;
32
- }
33
- const length = word.length;
34
- const chars = Array.from(word);
35
- const segments = Math.ceil(length / NGrams.NGRAM_SIZE);
36
- for (let i = 0; i < segments; i++) {
37
- let gram = "";
38
- for (let j = 0; j < NGrams.NGRAM_SIZE; j++) {
39
- const idx = i * NGrams.NGRAM_SIZE + j;
40
- if (idx < length) {
41
- gram += chars[idx];
42
- }
43
- }
44
- if (gram.length > 0) {
45
- unique.add(NGrams.javaHashCode(gram));
46
- }
47
- }
48
- }
49
- return Array.from(unique);
50
- }
51
- static buildWordList(source, separators) {
52
- if (!source) {
53
- return [];
54
- }
55
- const escaped = NGrams.escapeForRegex(separators);
56
- const regex = new RegExp("[" + escaped + "]+", "g");
57
- return source.split(regex).filter((token) => token.length > 0);
58
- }
59
- static escapeForRegex(value) {
60
- return value.replace(/[\\\-\[\]{}()*+?.,^$|#\s]/g, function (match) {
61
- return "\\" + match;
62
- });
63
- }
64
- static javaHashCode(value) {
65
- let hash = 0;
66
- for (let i = 0; i < value.length; i++) {
67
- hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
68
- }
69
- return hash;
70
- }
71
- }
72
- exports.NGrams = NGrams;
73
- //# sourceMappingURL=ngrams.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ngrams.js","sourceRoot":"","sources":["../ts/ngrams.ts"],"names":[],"mappings":"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"}