Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(yieldable-parser): parseAsync sometimes blocks for a *long* time #36 #37

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions test/async-index-of.js
lukas8219 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const tap = require('tap');
const { asyncIndexOf } = require('../utils/async-index-of');

const stringAsArray = ['s', 'o', 'm', 'e'];
const text = stringAsArray.join('');

tap.test('should return -1 if not found due to initialIndex', async () => {
const index = await asyncIndexOf(text, 's', 1);
const syncIndexOf = text.indexOf('s', 1);
tap.equal(index, syncIndexOf);
})

tap.test('should return proper index', async () => {
const index = await asyncIndexOf(text, 'e');
const syncIndexOf = text.indexOf('e');
tap.equal(index, syncIndexOf);
})

tap.test('should return proper test with initialIndex', async () => {
const index = await asyncIndexOf(text, 'e', 2);
const syncIndexOf = text.indexOf('e', 2);
tap.equal(index, syncIndexOf);
})

tap.test('should return correct indexOf if initialIndex is same', async () => {
const index = await asyncIndexOf(text, 'e', 3);
const syncIndexOf = text.indexOf('e', 3);
tap.equal(index, syncIndexOf);
})

tap.test('should return -1 if not found', async () => {
const index = await asyncIndexOf(text, 'x');
const syncIndexOf = text.indexOf('x');
tap.equal(index, syncIndexOf);
})
1 change: 1 addition & 0 deletions test/big-json-with-string copy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"titles":["É9075840612JËÍ "],"text":"Your operator's manuals \n\nDigital in the vehicle Familiarize yourself with the contents of the operator's manual directly via the vehicle's multimedia system (Menu item \"Vehicle\"). Start with the quick guide or deepen your knowledge with practical tips. \n\nVehicle document wallet in the vehicle Here you can find information on operation, service work and the warranty for your vehicle in printed form. \n\nSprinter \n\nOperating Instructions \n\n9075840612 \n\nOrder no. T907 0455 13 Part no. 907 584 06 12 Edition A-2023-2 \n\nFront passenger air bag warning \n\nAir bag warning sticker for USA and Canada \n\n& WARNING Risk of injury or fatal injuries if the front passenger air bag is enabled \n\nIf the front passenger air bag is enabled, a child on the front passenger seat may be struck by the front passenger air bag in the event of an accident. # NEVER use a rearward-facing child \n\nrestraint system on a seat with an ENA- BLED FRONT AIR BAG. This can result in the DEATH of or SERIOUS INJURY to the CHILD. \n\nObserve the chapter entitled \"Children in the vehi- cle\". \n\nPublication details \n\nInternet Further information about Mercedes-Benz vehicles and about Mercedes‑Benz AG can be found on the following websites: https://www.mercedes-benz.com https://www.mbusa.com (USA only) https://www.mercedes-benz.ca (Canada only) \n\nDocumentation team ©Daimler VANS USA, LLC ©Mercedes‑Benz AG: Not to be reprinted, transla- ted or otherwise reproduced, in whole or in part, without","unique":0,"loc":1,"id":"sec_76f277dd-8730-4376-a281-2b195c8930f4","sumid":"sum_b977530e-7227-49e2-900d-b2c68de38734"}
1 change: 1 addition & 0 deletions test/big-json-with-string.txt
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one may require attention into the JSON info. I copied and pasted from the shared file in the issue

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions test/test-parse-big-escaped-string.js
lukas8219 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

const yj = require('../index');
const tap = require('tap');
const { readFileSync } = require('fs');
//const str = readFileSync('./test/big-json-with-string.txt');
const str = readFileSync('./test/big-json-with-string copy.txt');
const nodeJSNativeParse = JSON.parse(str);

// Make sure the API works well without the optional parameters.
yj.parseAsync(str, (err, obj) => {
if (!err)
tap.equal(obj.text, nodeJSNativeParse.text, 'Failed to parse big string message - omitting logs', { diagnostic: true });
else
tap.fail(err);
});
21 changes: 21 additions & 0 deletions utils/async-index-of.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module.exports.indexOfGenerator = function* indexOfGenerator(stringInput, searchInput, initialIndex = 0) {
if (!stringInput || !stringInput.length) {
return -1;
}
stringInput = stringInput.slice(initialIndex);
let innerAt = 0;
let index = -1;
while (true) {
const at = Math.max(innerAt - 1, 0);
yield chunk = stringInput.slice(at, innerAt + 5000);
if (!chunk.length) {
return index;
}
const indexOf = chunk.indexOf(searchInput);
if (indexOf !== -1) {
yield index = indexOf + at + initialIndex;
return index;
}
innerAt += chunk.length + 1;
}
}
29 changes: 18 additions & 11 deletions yieldable-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* Multiple authors (IBM Corp.) - initial implementation and documentation
***************************************************************************/
'use strict';
const { indexOfGenerator } = require('./utils/async-index-of');

/**
* This method parses a JSON text to produce an object or array.
Expand Down Expand Up @@ -64,14 +65,16 @@ let parseWrapper = (text, reviver, intensity, cb) => {
};

// Process strings specially.
let normalizeUnicodedString = () => {
//not sure how i'll make it async
let normalizeUnicodedString = function*() {
let inQuotes = ' ';
let tempIndex = at;
let index = 0;
let slash = 0;
let c = '"';
while (c) {
index = parseStr.indexOf('"', tempIndex + 1);
//index = parseStr.indexOf('"', tempIndex + 1);
index = yield * indexOfGenerator(parseStr, '"', tempIndex + 1);
tempIndex = index;
ch = parseStr.charAt(tempIndex - 1);
while (ch === '\\') {
Expand All @@ -88,7 +91,8 @@ let parseWrapper = (text, reviver, intensity, cb) => {
}

// When parsing string values, look for " and \ characters.
index = inQuotes.indexOf('\\');
//index = inQuotes.indexOf('\\');
index = yield * indexOfGenerator(inQuotes, '\\');
while (index >= 0) {
let escapee = {
'"': '"',
Expand Down Expand Up @@ -124,7 +128,8 @@ let parseWrapper = (text, reviver, intensity, cb) => {
at = index + 1;
} else
break;
index = inQuotes.indexOf('\\', at);
//index = inQuotes.indexOf('\\', at);
index = yield * indexOfGenerator(inQuotes, '\\', at);
}
at = 0;
return inQuotes;
Expand Down Expand Up @@ -225,7 +230,7 @@ let parseWrapper = (text, reviver, intensity, cb) => {
return inQuotes;
} else {
seek();
return normalizeUnicodedString();
return yield * normalizeUnicodedString();
}
case '0':
case '1':
Expand Down Expand Up @@ -302,16 +307,15 @@ let parseWrapper = (text, reviver, intensity, cb) => {

let yielding = '';
// To hold 'parseYield' genarator function
function * yieldBridge() {
yielding = yield* parseYield();
async function * yieldBridge() {
lukas8219 marked this conversation as resolved.
Show resolved Hide resolved
yielding = yield* await parseYield();
}
let rs = yieldBridge();
let gen = rs.next();
rs.next().then((gen) => {

// Main yield control logic.
let yieldCPU = () => {
setImmediate(() => {
gen = rs.next();
setImmediate(async () => {
gen = await rs.next();

if (gen && gen.done === true) {
let isEmpty = (value) => {
Expand Down Expand Up @@ -339,6 +343,9 @@ let parseWrapper = (text, reviver, intensity, cb) => {
});
};
return yieldCPU();
});

// Main yield control logic.
};

exports.parseWrapper = parseWrapper;