officeparser 7.0.2 → 7.1.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.
- package/README.md +61 -2
- package/dist/OfficeConverter.d.ts +1 -1
- package/dist/OfficeParser.d.ts +1 -1
- package/dist/OfficeParser.js +9 -0
- package/dist/defaults.js +16 -1
- package/dist/generators/ChunkingGenerator.js +23 -3
- package/dist/generators/PdfGenerator.js +51 -4
- package/dist/generators/RtfGenerator.js +36 -17
- package/dist/officeparser.browser.d.ts +121 -4
- package/dist/officeparser.browser.iife.js +57 -53
- package/dist/officeparser.browser.mjs +57 -53
- package/dist/parsers/CsvParser.js +5 -0
- package/dist/parsers/ExcelParser.js +6 -2
- package/dist/parsers/HtmlParser.js +5 -0
- package/dist/parsers/MarkdownParser.js +5 -0
- package/dist/parsers/OpenOfficeParser.js +4 -0
- package/dist/parsers/PdfParser.js +3 -0
- package/dist/parsers/PowerPointParser.js +4 -0
- package/dist/parsers/RtfParser.js +2 -0
- package/dist/parsers/WordParser.js +4 -0
- package/dist/sbom.cdx.json +99 -99
- package/dist/types.d.ts +119 -2
- package/dist/types.js +3 -1
- package/dist/utils/configUtils.js +14 -1
- package/dist/utils/errorUtils.d.ts +20 -0
- package/dist/utils/errorUtils.js +37 -2
- package/dist/utils/moduleLoader.js +3 -3
- package/dist/utils/ocrUtils.js +271 -66
- package/dist/utils/xmlUtils.d.ts +8 -0
- package/dist/utils/xmlUtils.js +33 -1
- package/package.json +3 -2
package/dist/utils/ocrUtils.js
CHANGED
|
@@ -13,6 +13,24 @@
|
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
14
|
exports.terminateOcr = exports.performOcr = void 0;
|
|
15
15
|
const envUtils_js_1 = require("./envUtils.js");
|
|
16
|
+
const errorUtils_js_1 = require("./errorUtils.js");
|
|
17
|
+
/**
|
|
18
|
+
* Wraps a promise in a timeout.
|
|
19
|
+
*
|
|
20
|
+
* @param promise - The promise to wrap
|
|
21
|
+
* @param ms - Timeout duration in milliseconds
|
|
22
|
+
* @param errMsg - Error message to throw if timeout occurs
|
|
23
|
+
* @returns The wrapped promise
|
|
24
|
+
*/
|
|
25
|
+
function withTimeout(promise, ms, errMsg) {
|
|
26
|
+
let id;
|
|
27
|
+
const timeout = new Promise((_, reject) => {
|
|
28
|
+
id = setTimeout(() => {
|
|
29
|
+
reject(new Error(errMsg));
|
|
30
|
+
}, ms);
|
|
31
|
+
});
|
|
32
|
+
return Promise.race([promise, timeout]).then((res) => { clearTimeout(id); return res; }, (err) => { clearTimeout(id); throw err; });
|
|
33
|
+
}
|
|
16
34
|
/**
|
|
17
35
|
* Manages a pool of Tesseract workers with "Smart Affinity".
|
|
18
36
|
*
|
|
@@ -31,6 +49,7 @@ class OcrSchedulerManager {
|
|
|
31
49
|
MAX_WORKERS = 4;
|
|
32
50
|
idleTimeout = 10000; // 10s default
|
|
33
51
|
timeoutId = null;
|
|
52
|
+
isProcessing = false;
|
|
34
53
|
constructor() { }
|
|
35
54
|
/**
|
|
36
55
|
* Returns the singleton instance of the manager.
|
|
@@ -65,103 +84,289 @@ class OcrSchedulerManager {
|
|
|
65
84
|
* Performs OCR on an image using the smart worker pool.
|
|
66
85
|
*
|
|
67
86
|
* @param image - Image data (Buffer, string path, or Blob)
|
|
68
|
-
* @param config - OCR configuration (language, custom paths)
|
|
87
|
+
* @param config - OCR configuration (language, custom paths, timeouts, signal)
|
|
69
88
|
* @returns Recognized text
|
|
70
89
|
*/
|
|
71
90
|
async recognize(image, config) {
|
|
91
|
+
const signal = config?.abortSignal;
|
|
92
|
+
if (signal?.aborted) {
|
|
93
|
+
return Promise.reject((0, errorUtils_js_1.getAbortError)());
|
|
94
|
+
}
|
|
72
95
|
return new Promise((resolve, reject) => {
|
|
73
|
-
// Update idle timeout if provided
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
// Update idle timeout if provided.
|
|
97
|
+
// Priority: timeout.autoTerminate (new) > autoTerminateTimeout (deprecated) > built-in default.
|
|
98
|
+
const effectiveAutoTerminate = config?.timeout?.autoTerminate ?? config?.autoTerminateTimeout;
|
|
99
|
+
if (effectiveAutoTerminate !== undefined) {
|
|
100
|
+
this.idleTimeout = effectiveAutoTerminate;
|
|
76
101
|
}
|
|
77
102
|
// Reset the inactivity timer every time a new job is requested
|
|
78
103
|
this.resetIdleTimer();
|
|
104
|
+
let abortListener = null;
|
|
105
|
+
let finished = false;
|
|
106
|
+
let job;
|
|
107
|
+
const cleanResolve = (val) => {
|
|
108
|
+
if (finished)
|
|
109
|
+
return;
|
|
110
|
+
finished = true;
|
|
111
|
+
if (job)
|
|
112
|
+
job.isFinished = true;
|
|
113
|
+
if (abortListener && signal) {
|
|
114
|
+
signal.removeEventListener('abort', abortListener);
|
|
115
|
+
}
|
|
116
|
+
resolve(val);
|
|
117
|
+
};
|
|
118
|
+
const cleanReject = (err) => {
|
|
119
|
+
if (finished)
|
|
120
|
+
return;
|
|
121
|
+
finished = true;
|
|
122
|
+
if (job)
|
|
123
|
+
job.isFinished = true;
|
|
124
|
+
if (abortListener && signal) {
|
|
125
|
+
signal.removeEventListener('abort', abortListener);
|
|
126
|
+
}
|
|
127
|
+
reject(err);
|
|
128
|
+
};
|
|
129
|
+
// Priority: timeout.recognition (new) > 30 s default.
|
|
130
|
+
const recogTimeout = config?.timeout?.recognition ?? 30000;
|
|
131
|
+
// Create job
|
|
132
|
+
job = {
|
|
133
|
+
image,
|
|
134
|
+
config: config || {},
|
|
135
|
+
resolve: cleanResolve,
|
|
136
|
+
reject: cleanReject,
|
|
137
|
+
startTime: Date.now(),
|
|
138
|
+
timeoutMs: recogTimeout
|
|
139
|
+
};
|
|
140
|
+
if (signal) {
|
|
141
|
+
abortListener = () => {
|
|
142
|
+
if (finished)
|
|
143
|
+
return;
|
|
144
|
+
const err = (0, errorUtils_js_1.getAbortError)();
|
|
145
|
+
cleanReject(err);
|
|
146
|
+
// 1. Remove job from queue if it hasn't run yet
|
|
147
|
+
const idx = this.queue.indexOf(job);
|
|
148
|
+
if (idx !== -1) {
|
|
149
|
+
this.queue.splice(idx, 1);
|
|
150
|
+
}
|
|
151
|
+
// 2. Find if any worker is currently running this job and terminate/remove it
|
|
152
|
+
const workerIndex = this.pool.findIndex(mw => mw.activeJob === job);
|
|
153
|
+
if (workerIndex !== -1) {
|
|
154
|
+
const managedWorker = this.pool[workerIndex];
|
|
155
|
+
// Remove from pool immediately to prevent reuse
|
|
156
|
+
this.pool.splice(workerIndex, 1);
|
|
157
|
+
// Terminate the worker process
|
|
158
|
+
try {
|
|
159
|
+
managedWorker.worker.terminate();
|
|
160
|
+
}
|
|
161
|
+
catch (e) { }
|
|
162
|
+
// Trigger queue processing for subsequent tasks
|
|
163
|
+
this.processQueue();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
signal.addEventListener('abort', abortListener);
|
|
167
|
+
}
|
|
79
168
|
// Add job to queue and trigger processing
|
|
80
|
-
this.queue.push(
|
|
169
|
+
this.queue.push(job);
|
|
81
170
|
this.processQueue();
|
|
82
171
|
});
|
|
83
172
|
}
|
|
84
173
|
/**
|
|
85
174
|
* Attempts to process the next job in the queue using an available worker.
|
|
175
|
+
* Designed to be race-free and support concurrent/parallel job execution.
|
|
86
176
|
*/
|
|
87
177
|
async processQueue() {
|
|
88
|
-
if (this.
|
|
178
|
+
if (this.isProcessing)
|
|
89
179
|
return;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
180
|
+
this.isProcessing = true;
|
|
181
|
+
try {
|
|
182
|
+
while (this.queue.length > 0) {
|
|
183
|
+
const nextJob = this.queue[0];
|
|
184
|
+
if (nextJob.isFinished) {
|
|
185
|
+
this.queue.shift();
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
const requestedLanguage = nextJob.config.language || 'eng';
|
|
189
|
+
// 1. Find an idle worker with the EXACT language affinity
|
|
190
|
+
let managed = this.pool.find(mw => !mw.isBusy && mw.language === requestedLanguage);
|
|
191
|
+
// 2. If not found and we have room, create a new worker
|
|
192
|
+
if (!managed && this.pool.length < this.MAX_WORKERS) {
|
|
193
|
+
const job = this.queue.shift();
|
|
194
|
+
if (!job)
|
|
195
|
+
continue;
|
|
196
|
+
this.createAndRunWorker(job, requestedLanguage);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
// 3. If still not found and we are at capacity, find the LRU idle worker and re-initialize it
|
|
200
|
+
if (!managed) {
|
|
201
|
+
const idleWorkers = this.pool.filter(mw => !mw.isBusy);
|
|
202
|
+
if (idleWorkers.length > 0) {
|
|
203
|
+
const job = this.queue.shift();
|
|
204
|
+
if (!job)
|
|
205
|
+
continue;
|
|
206
|
+
managed = idleWorkers.reduce((prev, curr) => (prev.lastUsed < curr.lastUsed ? prev : curr));
|
|
207
|
+
this.reinitializeAndRunWorker(managed, job, requestedLanguage);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// 4. If we have a worker ready, execute the job
|
|
212
|
+
if (managed) {
|
|
213
|
+
const job = this.queue.shift();
|
|
214
|
+
if (!job)
|
|
215
|
+
continue;
|
|
216
|
+
this.runWorker(managed, job);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
// No workers can be allocated right now (all busy and pool at capacity). Break work loop.
|
|
220
|
+
break;
|
|
113
221
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
this.isProcessing = false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Helper to dynamically instantiate a Tesseract worker, register it to the pool, and run the job.
|
|
229
|
+
*/
|
|
230
|
+
async createAndRunWorker(job, requestedLanguage) {
|
|
231
|
+
// Priority: timeout.workerLoad (new) > 60 s default.
|
|
232
|
+
const loadTimeout = job.config.timeout?.workerLoad ?? 60000;
|
|
233
|
+
let managed = null;
|
|
234
|
+
try {
|
|
235
|
+
const { createWorker } = await import('tesseract.js');
|
|
236
|
+
const options = { logger: () => { } };
|
|
237
|
+
if (job.config.workerPath)
|
|
238
|
+
options.workerPath = job.config.workerPath;
|
|
239
|
+
if (job.config.corePath)
|
|
240
|
+
options.corePath = job.config.corePath;
|
|
241
|
+
if (job.config.langPath)
|
|
242
|
+
options.langPath = job.config.langPath;
|
|
243
|
+
const workerPromise = createWorker(requestedLanguage, 1, options);
|
|
244
|
+
// To prevent dangling worker threads on timeout or abort, we register a post-resolution hook
|
|
245
|
+
// that terminates the worker if the promise finishes after the timeout has fired or the job is finished.
|
|
246
|
+
let hasTimedOutOrAborted = false;
|
|
247
|
+
workerPromise.then(async (worker) => {
|
|
248
|
+
if (hasTimedOutOrAborted || job.isFinished) {
|
|
249
|
+
try {
|
|
250
|
+
await worker.terminate();
|
|
251
|
+
}
|
|
252
|
+
catch (e) { }
|
|
253
|
+
}
|
|
254
|
+
}, () => { });
|
|
255
|
+
const worker = loadTimeout > 0
|
|
256
|
+
? await withTimeout(workerPromise, loadTimeout, `OCR worker initialization timed out after ${loadTimeout}ms`).catch(err => {
|
|
257
|
+
hasTimedOutOrAborted = true;
|
|
258
|
+
throw err;
|
|
259
|
+
})
|
|
260
|
+
: await workerPromise;
|
|
261
|
+
// If the job finished/aborted while loading, clean up the worker and skip execution.
|
|
262
|
+
if (job.isFinished) {
|
|
263
|
+
hasTimedOutOrAborted = true;
|
|
264
|
+
try {
|
|
265
|
+
await worker.terminate();
|
|
266
|
+
}
|
|
267
|
+
catch (e) { }
|
|
268
|
+
this.processQueue();
|
|
118
269
|
return;
|
|
119
270
|
}
|
|
271
|
+
managed = {
|
|
272
|
+
worker,
|
|
273
|
+
language: requestedLanguage,
|
|
274
|
+
lastUsed: Date.now(),
|
|
275
|
+
isBusy: false
|
|
276
|
+
};
|
|
277
|
+
this.pool.push(managed);
|
|
278
|
+
await this.runWorker(managed, job);
|
|
120
279
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
280
|
+
catch (err) {
|
|
281
|
+
job.reject(err);
|
|
282
|
+
this.processQueue();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Helper to reinitialize an existing idle worker with a different language affinity and run the job.
|
|
287
|
+
*/
|
|
288
|
+
async reinitializeAndRunWorker(managed, job, requestedLanguage) {
|
|
289
|
+
// Priority: timeout.workerLoad (new) > 60 s default.
|
|
290
|
+
const loadTimeout = job.config.timeout?.workerLoad ?? 60000;
|
|
291
|
+
managed.isBusy = true;
|
|
292
|
+
managed.lastUsed = Date.now();
|
|
293
|
+
managed.activeJob = job;
|
|
294
|
+
try {
|
|
295
|
+
const reinitPromise = managed.worker.reinitialize(requestedLanguage);
|
|
296
|
+
if (loadTimeout > 0) {
|
|
297
|
+
await withTimeout(reinitPromise, loadTimeout, `OCR worker re-initialization timed out after ${loadTimeout}ms`);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
await reinitPromise;
|
|
301
|
+
}
|
|
302
|
+
managed.language = requestedLanguage;
|
|
303
|
+
// If the job finished/aborted while reinitializing, clean up and skip execution.
|
|
304
|
+
if (job.isFinished) {
|
|
305
|
+
const index = this.pool.indexOf(managed);
|
|
306
|
+
if (index !== -1) {
|
|
307
|
+
this.pool.splice(index, 1);
|
|
131
308
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
// we'll just fail this job and try another worker next time.
|
|
135
|
-
const job = this.queue.shift();
|
|
136
|
-
job?.reject(err);
|
|
137
|
-
this.processQueue();
|
|
138
|
-
return;
|
|
309
|
+
try {
|
|
310
|
+
await managed.worker.terminate();
|
|
139
311
|
}
|
|
312
|
+
catch (e) { }
|
|
313
|
+
this.processQueue();
|
|
314
|
+
return;
|
|
140
315
|
}
|
|
316
|
+
await this.runWorker(managed, job);
|
|
141
317
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
managed.lastUsed = Date.now();
|
|
318
|
+
catch (err) {
|
|
319
|
+
// Re-initialization failed/timed out, remove worker from pool and terminate
|
|
320
|
+
const index = this.pool.indexOf(managed);
|
|
321
|
+
if (index !== -1) {
|
|
322
|
+
this.pool.splice(index, 1);
|
|
323
|
+
}
|
|
149
324
|
try {
|
|
150
|
-
|
|
151
|
-
job.resolve(text);
|
|
325
|
+
await managed.worker.terminate();
|
|
152
326
|
}
|
|
153
|
-
catch (
|
|
154
|
-
|
|
327
|
+
catch (e) { }
|
|
328
|
+
job.reject(err);
|
|
329
|
+
this.processQueue();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Helper to execute OCR text recognition on the worker and return the results.
|
|
334
|
+
*/
|
|
335
|
+
async runWorker(managed, job) {
|
|
336
|
+
// Priority: timeout.recognition (new) > 30 s default.
|
|
337
|
+
const recogTimeout = job.config.timeout?.recognition ?? 30000;
|
|
338
|
+
managed.isBusy = true;
|
|
339
|
+
managed.lastUsed = Date.now();
|
|
340
|
+
managed.activeJob = job;
|
|
341
|
+
try {
|
|
342
|
+
const recognizePromise = managed.worker.recognize(job.image);
|
|
343
|
+
const { data: { text } } = recogTimeout > 0
|
|
344
|
+
? await withTimeout(recognizePromise, recogTimeout, `OCR recognition timed out after ${recogTimeout}ms`)
|
|
345
|
+
: await recognizePromise;
|
|
346
|
+
job.resolve(text);
|
|
347
|
+
}
|
|
348
|
+
catch (err) {
|
|
349
|
+
// If it timed out, terminate and remove worker to avoid reusing a stuck process
|
|
350
|
+
if (err.message?.includes('timed out')) {
|
|
351
|
+
const index = this.pool.indexOf(managed);
|
|
352
|
+
if (index !== -1) {
|
|
353
|
+
this.pool.splice(index, 1);
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
await managed.worker.terminate();
|
|
357
|
+
}
|
|
358
|
+
catch (e) { }
|
|
155
359
|
}
|
|
156
|
-
|
|
360
|
+
job.reject(err);
|
|
361
|
+
}
|
|
362
|
+
finally {
|
|
363
|
+
if (this.pool.includes(managed)) {
|
|
157
364
|
managed.isBusy = false;
|
|
365
|
+
managed.activeJob = undefined;
|
|
158
366
|
managed.lastUsed = Date.now();
|
|
159
|
-
// Check if there are more jobs waiting
|
|
160
|
-
this.processQueue();
|
|
161
367
|
}
|
|
368
|
+
this.processQueue();
|
|
162
369
|
}
|
|
163
|
-
// If no worker is available (all busy), the job stays in the queue
|
|
164
|
-
// and will be picked up when a worker finishes.
|
|
165
370
|
}
|
|
166
371
|
/**
|
|
167
372
|
* Terminates all workers in the pool and resets the state.
|
package/dist/utils/xmlUtils.d.ts
CHANGED
|
@@ -144,3 +144,11 @@ export declare const parseOfficeMetadata: (xmlContent: string) => OfficeMetadata
|
|
|
144
144
|
* ```
|
|
145
145
|
*/
|
|
146
146
|
export declare const parseOOXMLCustomProperties: (xmlContent: string) => Record<string, string | number | boolean | Date>;
|
|
147
|
+
/**
|
|
148
|
+
* Decodes XML entities (standard named entities, decimal, and hexadecimal entities) in a string.
|
|
149
|
+
* Useful when parsing content with regular expressions instead of a full DOM parser.
|
|
150
|
+
*
|
|
151
|
+
* @param text - The XML-encoded string
|
|
152
|
+
* @returns The decoded string
|
|
153
|
+
*/
|
|
154
|
+
export declare const decodeXmlEntities: (text: string) => string;
|
package/dist/utils/xmlUtils.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* @module xmlUtils
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.parseOOXMLCustomProperties = exports.parseOfficeMetadata = exports.getDirectChildren = exports.getAttribute = exports.getFirstElementByTagName = exports.getRawContent = exports.getSourceSubstring = exports.serializeXml = exports.getElementsByTagName = exports.parseXmlString = exports.isElement = void 0;
|
|
14
|
+
exports.decodeXmlEntities = exports.parseOOXMLCustomProperties = exports.parseOfficeMetadata = exports.getDirectChildren = exports.getAttribute = exports.getFirstElementByTagName = exports.getRawContent = exports.getSourceSubstring = exports.serializeXml = exports.getElementsByTagName = exports.parseXmlString = exports.isElement = void 0;
|
|
15
15
|
const xmldom_1 = require("@xmldom/xmldom");
|
|
16
16
|
const dateUtils_js_1 = require("./dateUtils.js");
|
|
17
17
|
/**
|
|
@@ -375,3 +375,35 @@ const parseOOXMLCustomProperties = (xmlContent) => {
|
|
|
375
375
|
return result;
|
|
376
376
|
};
|
|
377
377
|
exports.parseOOXMLCustomProperties = parseOOXMLCustomProperties;
|
|
378
|
+
/**
|
|
379
|
+
* Decodes XML entities (standard named entities, decimal, and hexadecimal entities) in a string.
|
|
380
|
+
* Useful when parsing content with regular expressions instead of a full DOM parser.
|
|
381
|
+
*
|
|
382
|
+
* @param text - The XML-encoded string
|
|
383
|
+
* @returns The decoded string
|
|
384
|
+
*/
|
|
385
|
+
const decodeXmlEntities = (text) => {
|
|
386
|
+
return text.replace(/&([^;]+);/g, (match, entity) => {
|
|
387
|
+
if (entity.startsWith('#')) {
|
|
388
|
+
if (entity[1] === 'x' || entity[1] === 'X') {
|
|
389
|
+
const hex = entity.slice(2);
|
|
390
|
+
const code = parseInt(hex, 16);
|
|
391
|
+
return !isNaN(code) ? String.fromCodePoint(code) : match;
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
const dec = entity.slice(1);
|
|
395
|
+
const code = parseInt(dec, 10);
|
|
396
|
+
return !isNaN(code) ? String.fromCodePoint(code) : match;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
switch (entity) {
|
|
400
|
+
case 'amp': return '&';
|
|
401
|
+
case 'lt': return '<';
|
|
402
|
+
case 'gt': return '>';
|
|
403
|
+
case 'quot': return '"';
|
|
404
|
+
case 'apos': return "'";
|
|
405
|
+
default: return match;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
};
|
|
409
|
+
exports.decodeXmlEntities = decodeXmlEntities;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "officeparser",
|
|
3
|
-
"version": "7.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "A robust, strictly-typed Node.js and Browser library for parsing office files (.docx, .pptx, .xlsx, .odt, .odp, .ods, .pdf, .rtf, .csv, .md, .html) and generating high-fidelity outputs in Markdown, HTML, CSV, RTF, and RAG-focused chunks.",
|
|
5
5
|
"funding": "https://github.com/sponsors/harshankur",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"build:browser:types": "dts-bundle-generator --no-check -o dist/officeparser.browser.d.ts src/index.ts",
|
|
30
30
|
"build:browser": "node build_browser.js && npm run sync:docs",
|
|
31
31
|
"sync:versions": "node scripts/sync-pdfjs-versions.js",
|
|
32
|
-
"sync:docs": "mkdir -p docs/dist && cp dist/officeparser.browser.iife.js docs/dist/ && cp dist/officeparser.browser.mjs docs/dist/",
|
|
32
|
+
"sync:docs": "mkdir -p docs/dist && cp dist/officeparser.browser.iife.js docs/dist/ && cp dist/officeparser.browser.mjs docs/dist/ && mkdir -p docs/test/files && cp test/files/* docs/test/files/",
|
|
33
33
|
"lint": "eslint src",
|
|
34
34
|
"test": "npm run lint && npm run test:clean && npm run build && npm run test:license && npm run test:artifacts && npm run test:parser && npm run test:generator",
|
|
35
35
|
"test:baseline": "npm run test:parser:baseline && npm run test:generator:baseline",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"test:generator": "npx tsx test/generator/testOfficeGenerator.ts",
|
|
39
39
|
"test:generator:baseline": "npx tsx test/generator/testOfficeGenerator.ts baseline",
|
|
40
40
|
"test:artifacts": "npx tsx test/testShippingArtifacts.ts",
|
|
41
|
+
"test:visualizer": "node test/testVisualizer.js",
|
|
41
42
|
"test:license": "npm run sbom && node scripts/validate-licenses.js",
|
|
42
43
|
"test:clean": "rm -rf test/results test/generator/results test/generator/output test/parser/results test/parser/output",
|
|
43
44
|
"clean": "rm -rf dist && npm run test:clean",
|