UNPKG

jsonpath-faster

Version:

Query JavaScript objects with JSONPath expressions. Compiles and caches JSONpath to JS

143 lines (126 loc) 3.82 kB
"use strict"; const genfun = require("generate-function"); const { makeTerminal } = require("../tokens"); // Provides a jsonpath interface for a given path const makePath = (jp, path, pragmas) => { const { compiler } = jp; const ast = jp.parse(path); const compileMethod = (ctx, ...tok) => { const code = compiler.compile([...ast, ...tok], ctx); const gen = genfun(); gen(`function(obj, count, extra, $) { ${code} }`); return gen.toFunction(); }; const makeMethod = (...tok) => { let counted, uncounted; return function(obj, count, $) { if (count !== undefined) { const m = (counted = counted || compileMethod({ counted: true }, ...tok)); return m(obj, count, undefined, $); } else { const m = (uncounted = uncounted || compileMethod({ counted: false }, ...tok)); return m(obj, count, undefined, $); } }; }; const makeGetSet = () => { let getter, setter; return function(obj, newValue, $) { if (newValue === undefined) { const m = (getter = getter || compileMethod( { counted: true }, makeTerminal(ctx => { ctx.preamble.push(`var value;`); ctx.appendix.push(`return value;`); return `value = @.value;`; }, pragmas) )); return m(obj, 1, newValue, $); } else { const m = (setter = setter || compileMethod( { counted: true }, makeTerminal(ctx => { ctx.appendix.push(`return extra;`); return `@.value = extra;`; }, pragmas) )); return m(obj, 1, newValue, $); } }; }; return { query: makeMethod( makeTerminal(ctx => { ctx.preamble.push(`var values = [];`); ctx.appendix.push(`return values;`); return `values.push(@.value);`; }, pragmas) ), paths: makeMethod( makeTerminal(ctx => { ctx.preamble.push(`var paths = [];`); ctx.appendix.push(`return paths;`); return `paths.push(@.path);`; }, pragmas) ), nodes: makeMethod( makeTerminal(ctx => { ctx.preamble.push(`var nodes = [];`); ctx.appendix.push(`return nodes;`); return `nodes.push({path: @.path, value: @.value});`; }, pragmas) ), value: makeGetSet(), parent(obj, $) { const m = compileMethod( { counted: true }, makeTerminal(ctx => { ctx.preamble.push(`var value;`); ctx.appendix.push(`return value;`); return `value = @.parent;`; }, pragmas) ); this.parent = (obj, $) => m(obj, 1, undefined, $); return this.parent(obj, $); }, apply(obj, fn, $) { const m = compileMethod( {}, makeTerminal(ctx => { ctx.preamble.push(`var nodes = [];`); ctx.appendix.push(`return nodes;`); const [r] = ctx.sym("r"); return ( `var ${r} = extra(@.value, @.path);` + `if (${r} !== undefined) @.value = ${r};` + `nodes.push({path: @.path, value: @.value});` ); }, pragmas) ); this.apply = (obj, fn, $) => m(obj, 0, fn, $); return this.apply(obj, fn, $); }, visit(obj, fn, $) { const m = compileMethod( {}, makeTerminal(ctx => { ctx.appendix.push(`return obj;`); const [r] = ctx.sym("r"); return ( `var ${r} = extra(@.value, @.path);` + `if (${r} !== undefined) @.value = ${r};` ); }, pragmas) ); this.visit = (obj, fn, $) => m(obj, 0, fn, $); return this.visit(obj, fn, $); } }; }; module.exports = makePath;