@iebh/reflib 2.5.6 → 2.5.8
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/.ignore +1 -1
- package/LICENSE +20 -20
- package/README.md +271 -271
- package/lib/browser.js +30 -30
- package/lib/default.js +30 -30
- package/lib/downloadFile.js +94 -94
- package/lib/fields.js +158 -158
- package/lib/formats.js +77 -77
- package/lib/getModule.js +39 -39
- package/lib/getRefDoi.js +16 -16
- package/lib/identifyFormat.js +13 -13
- package/lib/readFile.js +63 -63
- package/lib/readStream.js +21 -21
- package/lib/uploadFile.js +71 -71
- package/lib/writeFile.js +31 -31
- package/lib/writeStream.js +16 -16
- package/modules/default.js +6 -6
- package/modules/endnoteEnl.js +237 -237
- package/modules/endnoteEnlX.js +85 -85
- package/modules/endnoteXml.js +442 -435
- package/modules/interface.js +46 -46
- package/modules/json.js +79 -79
- package/modules/medline.js +638 -638
- package/modules/ris.js +366 -366
- package/modules/shims/JSONStream-browser.js +43 -43
- package/modules/shims/WritableStream-browser.js +51 -51
- package/package.json +65 -65
- package/shared/camelCase.js +17 -17
- package/shared/emitter.js +23 -23
- package/shared/streamEmitter.js +61 -61
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import Emitter from '../../shared/emitter.js';
|
|
2
|
-
|
|
3
|
-
export default class BrowserJSONStream {
|
|
4
|
-
constructor() {
|
|
5
|
-
this.text = '';
|
|
6
|
-
this.emitter = Emitter();
|
|
7
|
-
this.recNumber = 1;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
write(data) {
|
|
11
|
-
// CF: TODO: Parse data as it comes in chunks for better memory efficiency
|
|
12
|
-
this.text += data;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
end() {
|
|
16
|
-
try {
|
|
17
|
-
// Parse this.text as JSON
|
|
18
|
-
const jsonArray = JSON.parse(this.text);
|
|
19
|
-
|
|
20
|
-
// Free memory
|
|
21
|
-
this.text = '';
|
|
22
|
-
|
|
23
|
-
// For each entry in the json array (as ref):
|
|
24
|
-
if (Array.isArray(jsonArray))
|
|
25
|
-
jsonArray.forEach(ref => {
|
|
26
|
-
this.emitter.emit('data', ref);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Finished
|
|
30
|
-
this.emitter.emit('end');
|
|
31
|
-
} catch (e) {
|
|
32
|
-
console.error('Error parsing final JSON:', e);
|
|
33
|
-
this.emitter.emit('error', e);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
on(event, listener) {
|
|
38
|
-
this.emitter.on(event, listener);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static parse() {
|
|
42
|
-
return new BrowserJSONStream();
|
|
43
|
-
}
|
|
1
|
+
import Emitter from '../../shared/emitter.js';
|
|
2
|
+
|
|
3
|
+
export default class BrowserJSONStream {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.text = '';
|
|
6
|
+
this.emitter = Emitter();
|
|
7
|
+
this.recNumber = 1;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
write(data) {
|
|
11
|
+
// CF: TODO: Parse data as it comes in chunks for better memory efficiency
|
|
12
|
+
this.text += data;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
end() {
|
|
16
|
+
try {
|
|
17
|
+
// Parse this.text as JSON
|
|
18
|
+
const jsonArray = JSON.parse(this.text);
|
|
19
|
+
|
|
20
|
+
// Free memory
|
|
21
|
+
this.text = '';
|
|
22
|
+
|
|
23
|
+
// For each entry in the json array (as ref):
|
|
24
|
+
if (Array.isArray(jsonArray))
|
|
25
|
+
jsonArray.forEach(ref => {
|
|
26
|
+
this.emitter.emit('data', ref);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Finished
|
|
30
|
+
this.emitter.emit('end');
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error('Error parsing final JSON:', e);
|
|
33
|
+
this.emitter.emit('error', e);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
on(event, listener) {
|
|
38
|
+
this.emitter.on(event, listener);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static parse() {
|
|
42
|
+
return new BrowserJSONStream();
|
|
43
|
+
}
|
|
44
44
|
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
import Emitter from '../../shared/emitter.js';
|
|
2
|
-
import CacxParser from '@iebh/cacx';
|
|
3
|
-
|
|
4
|
-
export class WritableStream {
|
|
5
|
-
constructor(passedParserOptions) {
|
|
6
|
-
this.emitter = Emitter();
|
|
7
|
-
this.parser = new CacxParser({
|
|
8
|
-
collect: false,
|
|
9
|
-
reAttrSegment: /(?<key>[a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?<escape>["'])(?<val>.*?)\k<escape>)?/ig,
|
|
10
|
-
onTagOpen: (node) => {
|
|
11
|
-
const name = node.tag;
|
|
12
|
-
const attrs = node.attrs || {};
|
|
13
|
-
this.emitter.emit('opentag', name, attrs);
|
|
14
|
-
},
|
|
15
|
-
onTagClose: (node) => {
|
|
16
|
-
const name = node.tag;
|
|
17
|
-
// Emit text event before closing the tag
|
|
18
|
-
if (node.text && node.text.trim()) {
|
|
19
|
-
this.emitter.emit('text', node.text.trim());
|
|
20
|
-
}
|
|
21
|
-
this.emitter.emit('closetag', name);
|
|
22
|
-
},
|
|
23
|
-
flattenText: false,
|
|
24
|
-
keyText: 'text',
|
|
25
|
-
keyAttrs: 'attrs',
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Add event listeners to mimic htmlparser2 behavior
|
|
29
|
-
this.emitter.on('opentag', passedParserOptions.onopentag);
|
|
30
|
-
this.emitter.on('closetag', passedParserOptions.onclosetag);
|
|
31
|
-
this.emitter.on('text', passedParserOptions.ontext);
|
|
32
|
-
this.emitter.on('end', passedParserOptions.onend);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
write(data) {
|
|
36
|
-
this.parser.append(data).exec();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
end() {
|
|
40
|
-
// Process any remaining data
|
|
41
|
-
this.parser.exec();
|
|
42
|
-
|
|
43
|
-
// Emit text event for the last node if it has text
|
|
44
|
-
const lastNode = this.parser.stack.at(-1);
|
|
45
|
-
if (lastNode && lastNode.text && lastNode.text.trim()) {
|
|
46
|
-
this.emitter.emit('text', lastNode.text.trim());
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Emit end event
|
|
50
|
-
this.emitter.emit('end');
|
|
51
|
-
}
|
|
1
|
+
import Emitter from '../../shared/emitter.js';
|
|
2
|
+
import CacxParser from '@iebh/cacx';
|
|
3
|
+
|
|
4
|
+
export class WritableStream {
|
|
5
|
+
constructor(passedParserOptions) {
|
|
6
|
+
this.emitter = Emitter();
|
|
7
|
+
this.parser = new CacxParser({
|
|
8
|
+
collect: false,
|
|
9
|
+
reAttrSegment: /(?<key>[a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?<escape>["'])(?<val>.*?)\k<escape>)?/ig,
|
|
10
|
+
onTagOpen: (node) => {
|
|
11
|
+
const name = node.tag;
|
|
12
|
+
const attrs = node.attrs || {};
|
|
13
|
+
this.emitter.emit('opentag', name, attrs);
|
|
14
|
+
},
|
|
15
|
+
onTagClose: (node) => {
|
|
16
|
+
const name = node.tag;
|
|
17
|
+
// Emit text event before closing the tag
|
|
18
|
+
if (node.text && node.text.trim()) {
|
|
19
|
+
this.emitter.emit('text', node.text.trim());
|
|
20
|
+
}
|
|
21
|
+
this.emitter.emit('closetag', name);
|
|
22
|
+
},
|
|
23
|
+
flattenText: false,
|
|
24
|
+
keyText: 'text',
|
|
25
|
+
keyAttrs: 'attrs',
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Add event listeners to mimic htmlparser2 behavior
|
|
29
|
+
this.emitter.on('opentag', passedParserOptions.onopentag);
|
|
30
|
+
this.emitter.on('closetag', passedParserOptions.onclosetag);
|
|
31
|
+
this.emitter.on('text', passedParserOptions.ontext);
|
|
32
|
+
this.emitter.on('end', passedParserOptions.onend);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
write(data) {
|
|
36
|
+
this.parser.append(data).exec();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
end() {
|
|
40
|
+
// Process any remaining data
|
|
41
|
+
this.parser.exec();
|
|
42
|
+
|
|
43
|
+
// Emit text event for the last node if it has text
|
|
44
|
+
const lastNode = this.parser.stack.at(-1);
|
|
45
|
+
if (lastNode && lastNode.text && lastNode.text.trim()) {
|
|
46
|
+
this.emitter.emit('text', lastNode.text.trim());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Emit end event
|
|
50
|
+
this.emitter.emit('end');
|
|
51
|
+
}
|
|
52
52
|
}
|
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@iebh/reflib",
|
|
3
|
-
"version": "2.5.
|
|
4
|
-
"description": "Reference / Citation reference library utilities",
|
|
5
|
-
"scripts": {
|
|
6
|
-
"lint": "eslint .",
|
|
7
|
-
"test": "mocha",
|
|
8
|
-
"test:browser": "cd test/browser && npm run dev",
|
|
9
|
-
"test:watch": "nodemon --exec npm run test"
|
|
10
|
-
},
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/IEBH/Reflib.git"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"reflib",
|
|
17
|
-
"references",
|
|
18
|
-
"citations",
|
|
19
|
-
"library"
|
|
20
|
-
],
|
|
21
|
-
"author": "Matt Carter <m@ttcarter.com> (https://github.com/hash-bang)",
|
|
22
|
-
"contributors": [
|
|
23
|
-
"Connor Forbes <cforbes.software@gmail.com> (https://github.com/connorf25)"
|
|
24
|
-
],
|
|
25
|
-
"license": "MIT",
|
|
26
|
-
"bugs": {
|
|
27
|
-
"url": "https://github.com/IEBH/Reflib/issues"
|
|
28
|
-
},
|
|
29
|
-
"homepage": "https://github.com/IEBH/Reflib",
|
|
30
|
-
"enginesStrict": true,
|
|
31
|
-
"engines": {
|
|
32
|
-
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
33
|
-
},
|
|
34
|
-
"type": "module",
|
|
35
|
-
"exports": {
|
|
36
|
-
".": {
|
|
37
|
-
"browser": "./lib/browser.js",
|
|
38
|
-
"default": "./lib/default.js"
|
|
39
|
-
},
|
|
40
|
-
"./*": "./lib/*.js"
|
|
41
|
-
},
|
|
42
|
-
"browser": {
|
|
43
|
-
"htmlparser2/lib/WritableStream": "./modules/shims/WritableStream-browser.js",
|
|
44
|
-
"htmlparser2/lib/esm/WritableStream": "./modules/shims/WritableStream-browser.js",
|
|
45
|
-
"JSONStream": "./modules/shims/JSONStream-browser.js"
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@momsfriendlydevco/eslint-config": "^2.3.1",
|
|
49
|
-
"chai": "^5.2.0",
|
|
50
|
-
"eslint": "^9.31.0",
|
|
51
|
-
"mocha": "^11.1.0",
|
|
52
|
-
"mocha-logger": "^1.0.8",
|
|
53
|
-
"nodemon": "^3.1.9",
|
|
54
|
-
"temp": "^0.9.4",
|
|
55
|
-
"vite-plugin-replace": "^0.1.1"
|
|
56
|
-
},
|
|
57
|
-
"dependencies": {
|
|
58
|
-
"@iebh/cacx": "^1.0.3",
|
|
59
|
-
"@zip.js/zip.js": "^2.7.57",
|
|
60
|
-
"htmlparser2": "^9.1.0",
|
|
61
|
-
"JSONStream": "^1.3.5",
|
|
62
|
-
"mitt": "^3.0.1",
|
|
63
|
-
"sql.js": "^1.12.0"
|
|
64
|
-
}
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@iebh/reflib",
|
|
3
|
+
"version": "2.5.8",
|
|
4
|
+
"description": "Reference / Citation reference library utilities",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint .",
|
|
7
|
+
"test": "mocha",
|
|
8
|
+
"test:browser": "cd test/browser && npm run dev",
|
|
9
|
+
"test:watch": "nodemon --exec npm run test"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/IEBH/Reflib.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"reflib",
|
|
17
|
+
"references",
|
|
18
|
+
"citations",
|
|
19
|
+
"library"
|
|
20
|
+
],
|
|
21
|
+
"author": "Matt Carter <m@ttcarter.com> (https://github.com/hash-bang)",
|
|
22
|
+
"contributors": [
|
|
23
|
+
"Connor Forbes <cforbes.software@gmail.com> (https://github.com/connorf25)"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/IEBH/Reflib/issues"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/IEBH/Reflib",
|
|
30
|
+
"enginesStrict": true,
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
33
|
+
},
|
|
34
|
+
"type": "module",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"browser": "./lib/browser.js",
|
|
38
|
+
"default": "./lib/default.js"
|
|
39
|
+
},
|
|
40
|
+
"./*": "./lib/*.js"
|
|
41
|
+
},
|
|
42
|
+
"browser": {
|
|
43
|
+
"htmlparser2/lib/WritableStream": "./modules/shims/WritableStream-browser.js",
|
|
44
|
+
"htmlparser2/lib/esm/WritableStream": "./modules/shims/WritableStream-browser.js",
|
|
45
|
+
"JSONStream": "./modules/shims/JSONStream-browser.js"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@momsfriendlydevco/eslint-config": "^2.3.1",
|
|
49
|
+
"chai": "^5.2.0",
|
|
50
|
+
"eslint": "^9.31.0",
|
|
51
|
+
"mocha": "^11.1.0",
|
|
52
|
+
"mocha-logger": "^1.0.8",
|
|
53
|
+
"nodemon": "^3.1.9",
|
|
54
|
+
"temp": "^0.9.4",
|
|
55
|
+
"vite-plugin-replace": "^0.1.1"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"@iebh/cacx": "^1.0.3",
|
|
59
|
+
"@zip.js/zip.js": "^2.7.57",
|
|
60
|
+
"htmlparser2": "^9.1.0",
|
|
61
|
+
"JSONStream": "^1.3.5",
|
|
62
|
+
"mitt": "^3.0.1",
|
|
63
|
+
"sql.js": "^1.12.0"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/shared/camelCase.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Camel case any input string
|
|
3
|
-
* This is functionally the same as Lodash's camelCase() function
|
|
4
|
-
*
|
|
5
|
-
* @param {string} input The input string to camelize
|
|
6
|
-
* @returns {string} The input string in camelCase format
|
|
7
|
-
* @url https://github.com/MomsFriendlyDevCo/Nodash
|
|
8
|
-
*/
|
|
9
|
-
export default function(input) {
|
|
10
|
-
return input
|
|
11
|
-
.split(/[\s-]/)
|
|
12
|
-
.map((word, offset) => offset == 0
|
|
13
|
-
? word.toLowerCase()
|
|
14
|
-
: word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase()
|
|
15
|
-
)
|
|
16
|
-
.join('')
|
|
17
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Camel case any input string
|
|
3
|
+
* This is functionally the same as Lodash's camelCase() function
|
|
4
|
+
*
|
|
5
|
+
* @param {string} input The input string to camelize
|
|
6
|
+
* @returns {string} The input string in camelCase format
|
|
7
|
+
* @url https://github.com/MomsFriendlyDevCo/Nodash
|
|
8
|
+
*/
|
|
9
|
+
export default function(input) {
|
|
10
|
+
return input
|
|
11
|
+
.split(/[\s-]/)
|
|
12
|
+
.map((word, offset) => offset == 0
|
|
13
|
+
? word.toLowerCase()
|
|
14
|
+
: word.substr(0, 1).toUpperCase() + word.substr(1).toLowerCase()
|
|
15
|
+
)
|
|
16
|
+
.join('')
|
|
17
|
+
}
|
package/shared/emitter.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import Mitt from 'mitt';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Generic wrapper for an event emitter
|
|
5
|
-
* This module returns a wrapped version of `mitt` stand-alone event emitter (+ support for method chaining)
|
|
6
|
-
*
|
|
7
|
-
* @returns {Object} A wrapped version of the NPM Mitt event emitter with chainable functionality
|
|
8
|
-
*/
|
|
9
|
-
export default function emitter() {
|
|
10
|
-
let emitter = Mitt();
|
|
11
|
-
|
|
12
|
-
// Add method chaining
|
|
13
|
-
emitter.mitt = {};
|
|
14
|
-
['on', 'off', 'emit'].forEach(f => {
|
|
15
|
-
emitter.mitt[f] = emitter[f]; // Backup old function into `.mitt.${F}`
|
|
16
|
-
emitter[f] = (...args) => {
|
|
17
|
-
emitter.mitt[f](...args);
|
|
18
|
-
return emitter;
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
return emitter;
|
|
23
|
-
}
|
|
1
|
+
import Mitt from 'mitt';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generic wrapper for an event emitter
|
|
5
|
+
* This module returns a wrapped version of `mitt` stand-alone event emitter (+ support for method chaining)
|
|
6
|
+
*
|
|
7
|
+
* @returns {Object} A wrapped version of the NPM Mitt event emitter with chainable functionality
|
|
8
|
+
*/
|
|
9
|
+
export default function emitter() {
|
|
10
|
+
let emitter = Mitt();
|
|
11
|
+
|
|
12
|
+
// Add method chaining
|
|
13
|
+
emitter.mitt = {};
|
|
14
|
+
['on', 'off', 'emit'].forEach(f => {
|
|
15
|
+
emitter.mitt[f] = emitter[f]; // Backup old function into `.mitt.${F}`
|
|
16
|
+
emitter[f] = (...args) => {
|
|
17
|
+
emitter.mitt[f](...args);
|
|
18
|
+
return emitter;
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return emitter;
|
|
23
|
+
}
|
package/shared/streamEmitter.js
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import Emitter from '../shared/emitter.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Wrapper for streams which transforms a given input into an emitter pattern
|
|
5
|
-
* This is designed to let regular `node:stream.Readable` objects pass through without alteration but browser based stream objects get wrapped
|
|
6
|
-
* @param {stream.Readable|ReadableStream} inStream The input stream to wrap
|
|
7
|
-
* @returns {stream.Readable|Emitter} Either the unedited node compatible stream or an event emitter with the same behaviour
|
|
8
|
-
*
|
|
9
|
-
* @emits data Emitted as `(chunk)` on each data chunk
|
|
10
|
-
* @emits end Emitted as `()` when the input stream has closed
|
|
11
|
-
* @emits error Emitted as `(Error)` on any read error
|
|
12
|
-
*/
|
|
13
|
-
export default function streamEmitter (inStream) {
|
|
14
|
-
if (inStream.getReader) { // Assume browser compatible ReadableStream
|
|
15
|
-
/**
|
|
16
|
-
* MC's tiny ReadableStream -> stream.Readable / Emitter pattern
|
|
17
|
-
* There is a non-zero chance that this is going to break at some future point
|
|
18
|
-
* This is really just a shiv for browser functionality to replicate Stream-a-like emitter pattern
|
|
19
|
-
* @date 2023-10-19
|
|
20
|
-
* @author Matt Carter <m@ttcarter.com>
|
|
21
|
-
*/
|
|
22
|
-
let reader = new Emitter();
|
|
23
|
-
Object.assign(reader, {
|
|
24
|
-
isBrowser: true, // Tells us we are in browser env
|
|
25
|
-
bytesRead: 0,
|
|
26
|
-
reader: inStream.getReader(),
|
|
27
|
-
textDecoder: new TextDecoder('utf-8'),
|
|
28
|
-
read() { // Read one chunk + trigger emitters
|
|
29
|
-
this.reader.read()
|
|
30
|
-
.then(({done, value}) => {
|
|
31
|
-
if (done) {
|
|
32
|
-
reader.emit('end');
|
|
33
|
-
|
|
34
|
-
if (this.pipeTarget)
|
|
35
|
-
this.pipeTarget.end();
|
|
36
|
-
} else if (value) {
|
|
37
|
-
let data = this.textDecoder.decode(value);
|
|
38
|
-
this.bytesRead += data.length;
|
|
39
|
-
reader.emit('data', data);
|
|
40
|
-
|
|
41
|
-
if (this.pipeTarget)
|
|
42
|
-
this.pipeTarget.write(data);
|
|
43
|
-
|
|
44
|
-
setTimeout(this.read.bind(this));
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
.catch(e => this.emit('error', e))
|
|
48
|
-
},
|
|
49
|
-
pipeTarget: null,
|
|
50
|
-
pipe(target) {
|
|
51
|
-
this.pipeTarget = target;
|
|
52
|
-
return this;
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
setTimeout(()=> reader.read());
|
|
57
|
-
return reader;
|
|
58
|
-
} else { // Assume Node native stream.Readable
|
|
59
|
-
return inStream;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
import Emitter from '../shared/emitter.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper for streams which transforms a given input into an emitter pattern
|
|
5
|
+
* This is designed to let regular `node:stream.Readable` objects pass through without alteration but browser based stream objects get wrapped
|
|
6
|
+
* @param {stream.Readable|ReadableStream} inStream The input stream to wrap
|
|
7
|
+
* @returns {stream.Readable|Emitter} Either the unedited node compatible stream or an event emitter with the same behaviour
|
|
8
|
+
*
|
|
9
|
+
* @emits data Emitted as `(chunk)` on each data chunk
|
|
10
|
+
* @emits end Emitted as `()` when the input stream has closed
|
|
11
|
+
* @emits error Emitted as `(Error)` on any read error
|
|
12
|
+
*/
|
|
13
|
+
export default function streamEmitter (inStream) {
|
|
14
|
+
if (inStream.getReader) { // Assume browser compatible ReadableStream
|
|
15
|
+
/**
|
|
16
|
+
* MC's tiny ReadableStream -> stream.Readable / Emitter pattern
|
|
17
|
+
* There is a non-zero chance that this is going to break at some future point
|
|
18
|
+
* This is really just a shiv for browser functionality to replicate Stream-a-like emitter pattern
|
|
19
|
+
* @date 2023-10-19
|
|
20
|
+
* @author Matt Carter <m@ttcarter.com>
|
|
21
|
+
*/
|
|
22
|
+
let reader = new Emitter();
|
|
23
|
+
Object.assign(reader, {
|
|
24
|
+
isBrowser: true, // Tells us we are in browser env
|
|
25
|
+
bytesRead: 0,
|
|
26
|
+
reader: inStream.getReader(),
|
|
27
|
+
textDecoder: new TextDecoder('utf-8'),
|
|
28
|
+
read() { // Read one chunk + trigger emitters
|
|
29
|
+
this.reader.read()
|
|
30
|
+
.then(({done, value}) => {
|
|
31
|
+
if (done) {
|
|
32
|
+
reader.emit('end');
|
|
33
|
+
|
|
34
|
+
if (this.pipeTarget)
|
|
35
|
+
this.pipeTarget.end();
|
|
36
|
+
} else if (value) {
|
|
37
|
+
let data = this.textDecoder.decode(value);
|
|
38
|
+
this.bytesRead += data.length;
|
|
39
|
+
reader.emit('data', data);
|
|
40
|
+
|
|
41
|
+
if (this.pipeTarget)
|
|
42
|
+
this.pipeTarget.write(data);
|
|
43
|
+
|
|
44
|
+
setTimeout(this.read.bind(this));
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.catch(e => this.emit('error', e))
|
|
48
|
+
},
|
|
49
|
+
pipeTarget: null,
|
|
50
|
+
pipe(target) {
|
|
51
|
+
this.pipeTarget = target;
|
|
52
|
+
return this;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
setTimeout(()=> reader.read());
|
|
57
|
+
return reader;
|
|
58
|
+
} else { // Assume Node native stream.Readable
|
|
59
|
+
return inStream;
|
|
60
|
+
}
|
|
61
|
+
}
|