diff --git a/src/filters/filter.js b/src/filters/filter.js index f872bde..f32fc70 100644 --- a/src/filters/filter.js +++ b/src/filters/filter.js @@ -24,15 +24,22 @@ const filter = options => { for (let i = previousStack.length - 1; i > commonLength; --i) { returnTokens.push({name: typeof previousStack[i] == 'number' ? 'endArray' : 'endObject'}); } + + // update the index if (commonLength < previousStack.length) { if (commonLength < stack.length) { const key = stack[commonLength]; if (typeof key == 'string') { if (options?.streamKeys) { - returnTokens.push({name: 'startKey'}, {name: 'stringChunk', value: key}, {name: 'endKey'}, {name: 'keyValue', value: key}); - } else { + returnTokens.push({name: 'startKey'}, {name: 'stringChunk', value: key}, {name: 'endKey'}); + } + if (options?.packKeys || !options?.streamKeys) { returnTokens.push({name: 'keyValue', value: key}); } + } else if (typeof key == 'number' && options?.skippedArrayValue) { + for (let i = Math.max(0, previousStack[commonLength] + 1); i < key; ++i) { + returnTokens.push(...options.skippedArrayValue); + } } previousStack[commonLength] = key; ++commonLength; @@ -49,19 +56,26 @@ const filter = options => { const key = stack[i]; previousStack.push(key); if (typeof key == 'number') { - if (key >= 0) returnTokens.push({name: 'startArray'}); + if (key >= 0) { + returnTokens.push({name: 'startArray'}); + if (options?.skippedArrayValue) { + for (let j = 0; j < key; ++j) { + returnTokens.push(...options.skippedArrayValue); + } + } + } } else if (typeof key == 'string') { + returnTokens.push({name: 'startObject'}); if (options?.streamKeys) { - returnTokens.push({name: 'startObject'}, {name: 'startKey'}, {name: 'stringChunk', value: key}, {name: 'endKey'}, {name: 'keyValue', value: key}); - } else { - returnTokens.push({name: 'startObject'}, {name: 'keyValue', value: key}); + returnTokens.push({name: 'startKey'}, {name: 'stringChunk', value: key}, {name: 'endKey'}); + } + if (options?.packKeys || !options?.streamKeys) { + returnTokens.push({name: 'keyValue', value: key}); } } } // save the stack - // previousStack = stack.slice(); - // previousStack.splice(commonLength, previousStack.length - commonLength, ...stack.slice(commonLength)); switch (chunk?.name) { case 'startObject': previousStack.push(null); @@ -79,5 +93,5 @@ const filter = options => { module.exports = filter; module.exports.filter = filter; -module.exports.withParser = options => withParser(filter, options); -module.exports.withParserAsStream = options => withParser.asStream(filter, options); +module.exports.withParser = options => withParser(filter, Object.assign({packKeys: true}, options)); +module.exports.withParserAsStream = options => withParser.asStream(filter, Object.assign({packKeys: true}, options)); diff --git a/src/filters/pick.js b/src/filters/pick.js index d073b3a..734c29a 100644 --- a/src/filters/pick.js +++ b/src/filters/pick.js @@ -10,5 +10,5 @@ const pick = filterBase(); module.exports = pick; module.exports.pick = pick; -module.exports.withParser = options => withParser(pick, options); -module.exports.withParserAsStream = options => withParser.asStream(pick, options); +module.exports.withParser = options => withParser(pick, Object.assign({packKeys: true}, options)); +module.exports.withParserAsStream = options => withParser.asStream(pick, Object.assign({packKeys: true}, options)); diff --git a/tests/test-filter.mjs b/tests/test-filter.mjs index 6c8ce55..6bc194a 100644 --- a/tests/test-filter.mjs +++ b/tests/test-filter.mjs @@ -10,7 +10,7 @@ import readString from './read-string.mjs'; test.asPromise('filter', (t, resolve, reject) => { const input = '{"a": 1, "b": true, "c": ["d"]}', - pipeline = chain([readString(input), filter.withParser({packKeys: true, packValues: false, filter: /^(|a|c)$/})]), + pipeline = chain([readString(input), filter.withParser({packValues: false, filter: /^(|a|c)$/})]), result = []; pipeline.on('data', chunk => result.push(chunk)); @@ -39,7 +39,7 @@ test.asPromise('filter', (t, resolve, reject) => { test.asPromise('filter: no streaming', (t, resolve, reject) => { const input = '{"a": 1, "b": true, "c": ["d"]}', - pipeline = chain([readString(input), filter.withParser({packKeys: true, packValues: false, streamValues: false, filter: /^(a|c)$/})]), + pipeline = chain([readString(input), filter.withParser({packValues: false, streamValues: false, filter: /^(a|c)$/})]), result = []; pipeline.on('data', chunk => result.push(chunk)); @@ -94,6 +94,27 @@ test.asPromise('filter: array', (t, resolve, reject) => { pipeline.resume(); }); +test.asPromise('filter: array with skipped values', (t, resolve, reject) => { + const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + asm = assembler(), + pipeline = chain([ + readString(JSON.stringify(data)), + filter.withParser({ + filter: stack => stack.length == 1 && typeof stack[0] == 'number' && stack[0] % 2, + skippedArrayValue: [{name: 'nullValue', value: null}] + }), + asm.tapChain + ]); + + pipeline.on('error', reject); + pipeline.on('end', () => { + t.deepEqual(asm.current, [null, 2, null, 4, null, 6, null, 8, null, 10]); + resolve(); + }); + + pipeline.resume(); +}); + test.asPromise('filter: bug46', (t, resolve, reject) => { const data = [ {data: {a: 1, b: 2}, x: 1}, diff --git a/tests/test-pick.mjs b/tests/test-pick.mjs index 35e4a6f..675c62e 100644 --- a/tests/test-pick.mjs +++ b/tests/test-pick.mjs @@ -34,6 +34,7 @@ test.asPromise('parser: pick events', (t, resolve, reject) => { 'startKey', 'stringChunk', 'endKey', + 'keyValue', 'trueValue', 'endObject' ]);