From 8de9fdfab3c53fc94db6cb22ec99cfabe3590812 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Mon, 20 May 2024 17:29:55 +0300 Subject: [PATCH 01/12] implemented the jq modifications with a temporary keyWord --- lib/template.js | 122 ++++++++++--- test/template.test.js | 412 ++++++++++++++++++++++++++---------------- 2 files changed, 352 insertions(+), 182 deletions(-) diff --git a/lib/template.js b/lib/template.js index cf4016e..7b3331c 100644 --- a/lib/template.js +++ b/lib/template.js @@ -1,4 +1,4 @@ -const jq = require('./jq'); +const jq = require("./jq"); const findInsideDoubleBracesIndices = (input) => { let wrappingQuote = null; @@ -8,7 +8,7 @@ const findInsideDoubleBracesIndices = (input) => { for (let i = 0; i < input.length; i += 1) { const char = input[i]; - if (insideDoubleBracesStart && char === '\\') { + if (insideDoubleBracesStart && char === "\\") { // If next character is escaped, skip it i += 1; } @@ -19,40 +19,62 @@ const findInsideDoubleBracesIndices = (input) => { } else if (wrappingQuote === char) { wrappingQuote = null; } - } else if (!wrappingQuote && char === '{' && i > 0 && input[i - 1] === '{') { + } else if ( + !wrappingQuote && + char === "{" && + i > 0 && + input[i - 1] === "{" + ) { // if opening double braces that not wrapped with quotes if (insideDoubleBracesStart) { - throw new Error(`Found double braces in index ${i - 1} inside other one in index ${insideDoubleBracesStart - '{{'.length}`); + throw new Error( + `Found double braces in index ${i - 1} inside other one in index ${ + insideDoubleBracesStart - "{{".length + }` + ); } insideDoubleBracesStart = i + 1; - if (input[i + 1] === '{') { + if (input[i + 1] === "{") { // To overcome three "{" in a row considered as two different opening double braces i += 1; } - } else if (!wrappingQuote && char === '}' && i > 0 && input[i - 1] === '}') { + } else if ( + !wrappingQuote && + char === "}" && + i > 0 && + input[i - 1] === "}" + ) { // if closing double braces that not wrapped with quotes if (insideDoubleBracesStart) { - indices.push({start: insideDoubleBracesStart, end: i - 1}); + indices.push({ start: insideDoubleBracesStart, end: i - 1 }); insideDoubleBracesStart = null; - if (input[i + 1] === '}') { + if (input[i + 1] === "}") { // To overcome three "}" in a row considered as two different closing double braces i += 1; } } else { - throw new Error(`Found closing double braces in index ${i - 1} without opening double braces`); + throw new Error( + `Found closing double braces in index ${ + i - 1 + } without opening double braces` + ); } } } if (insideDoubleBracesStart) { - throw new Error(`Found opening double braces in index ${insideDoubleBracesStart - '{{'.length} without closing double braces`); + throw new Error( + `Found opening double braces in index ${ + insideDoubleBracesStart - "{{".length + } without closing double braces` + ); } return indices; -} +}; const render = (inputJson, template, execOptions = {}) => { - if (typeof template !== 'string') { + if (typeof template !== "string") { return null; } const indices = findInsideDoubleBracesIndices(template); @@ -62,51 +84,93 @@ const render = (inputJson, template, execOptions = {}) => { } const firstIndex = indices[0]; - if (indices.length === 1 && template.trim().startsWith('{{') && template.trim().endsWith('}}')) { + if ( + indices.length === 1 && + template.trim().startsWith("{{") && + template.trim().endsWith("}}") + ) { // If entire string is a template, evaluate and return the result with the original type - return jq.exec(inputJson, template.slice(firstIndex.start, firstIndex.end), execOptions); + return jq.exec( + inputJson, + template.slice(firstIndex.start, firstIndex.end), + execOptions + ); } - let result = template.slice(0, firstIndex.start - '{{'.length); // Initiate result with string until first template start index + let result = template.slice(0, firstIndex.start - "{{".length); // Initiate result with string until first template start index indices.forEach((index, i) => { - const jqResult = jq.exec(inputJson, template.slice(index.start, index.end), execOptions); + const jqResult = jq.exec( + inputJson, + template.slice(index.start, index.end), + execOptions + ); result += // Add to the result the stringified evaluated jq of the current template - (typeof jqResult === 'string' ? jqResult : JSON.stringify(jqResult)) + + (typeof jqResult === "string" ? jqResult : JSON.stringify(jqResult)) + // Add to the result from template end index. if last template index - until the end of string, else until next start index template.slice( - index.end + '}}'.length, - i + 1 === indices.length ? template.length : indices[i + 1].start - '{{'.length, + index.end + "}}".length, + i + 1 === indices.length + ? template.length + : indices[i + 1].start - "{{".length ); }); return result; -} +}; const renderRecursively = (inputJson, template, execOptions = {}) => { - if (typeof template === 'string') { + if (typeof template === "string") { return render(inputJson, template, execOptions); } if (Array.isArray(template)) { - return template.map((value) => renderRecursively(inputJson, value, execOptions)); + return template.map((value) => + renderRecursively(inputJson, value, execOptions) + ); } - if (typeof template === 'object' && template !== null) { + if (typeof template === "object" && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { + const MY_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; + const keywordMatcher = `\\{\\{\\s*${MY_KEYWORD_ESCAPED}\\s*\\}\\}`; + + if (key.match(keywordMatcher)) { + const evaluatedValue = renderRecursively( + inputJson, + value, + execOptions + ); + if (typeof evaluatedValue !== "object") { + throw new Error( + `Evaluated value should be an object if the key is ${key}. Original value: ${value}, evaluated to: ${JSON.stringify( + evaluatedValue + )}` + ); + } + return Object.entries(evaluatedValue); + } + const evaluatedKey = renderRecursively(inputJson, key, execOptions); - if (!['undefined', 'string'].includes(typeof evaluatedKey) && evaluatedKey !== null) { + if ( + !["undefined", "string"].includes(typeof evaluatedKey) && + evaluatedKey !== null + ) { throw new Error( - `Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify(evaluatedKey)}`, + `Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify( + evaluatedKey + )}` ); } - return evaluatedKey ? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]] : []; - }), + return evaluatedKey + ? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]] + : []; + }) ); } return template; -} +}; module.exports = { - renderRecursively + renderRecursively, }; diff --git a/test/template.test.js b/test/template.test.js index 69c7fee..337534c 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -1,170 +1,276 @@ -const jq = require('../lib'); +const jq = require("../lib"); -describe('template', () => { - it('should break', () => { - const json = { foo2: 'bar' }; - const input = '{{.foo}}'; - const result = jq.renderRecursively(json, input); +describe("template", () => { + it("should break", () => { + const json = { foo2: "bar" }; + const input = "{{.foo}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe(null); - }); - it('non template should work', () => { - const json = { foo2: 'bar' }; - const render = (input) => jq.renderRecursively(json, input); - - expect(render(123)).toBe(123); - expect(render(undefined)).toBe(undefined); - expect(render(null)).toBe(null); - expect(render(true)).toBe(true); - expect(render(false)).toBe(false); - }); - it('different types should work', () => { - const input = '{{.foo}}'; - const render = (json) => jq.renderRecursively(json, input); - - expect(render({ foo: 'bar' })).toBe('bar'); - expect(render({ foo: 1 })).toBe(1); - expect(render({ foo: true })).toBe(true); - expect(render({ foo: null })).toBe(null); - expect(render({ foo: undefined })).toBe(null); - expect(render({ foo: ['bar'] })).toEqual(['bar']); - expect(render({ foo: [{ bar: 'bar' }] })).toEqual([{ bar: 'bar' }]); - expect(render({ foo: {prop1: "1"} })).toEqual({prop1: "1"}); - expect(render({ foo: {obj: { obj2: { num: 1, string: "str"} }} })).toEqual({obj: { obj2: { num: 1, string: "str"} }}); - expect(render({ foo: { obj: { obj2: { num: 1, string: "str", bool: true} }} })).toEqual({ obj: { obj2: { num: 1, string: "str", bool: true} }}); - }); - it ('should return undefined', () => { - const json = { foo: 'bar' }; - const input = '{{empty}}'; - const result = jq.renderRecursively(json, input); + expect(result).toBe(null); + }); + it("non template should work", () => { + const json = { foo2: "bar" }; + const render = (input) => jq.renderRecursively(json, input); - expect(result).toBe(undefined); - }); - it ('should return null on invalid json', () => { - const json = "foo"; - const input = '{{.foo}}'; - const result = jq.renderRecursively(json, input); + expect(render(123)).toBe(123); + expect(render(undefined)).toBe(undefined); + expect(render(null)).toBe(null); + expect(render(true)).toBe(true); + expect(render(false)).toBe(false); + }); + it("different types should work", () => { + const input = "{{.foo}}"; + const render = (json) => jq.renderRecursively(json, input); - expect(result).toBe(null); - }); - it('should excape \'\' to ""', () => { - const json = { foo: 'com' }; - const input = "{{'https://url.' + .foo}}"; - const result = jq.renderRecursively(json, input); + expect(render({ foo: "bar" })).toBe("bar"); + expect(render({ foo: 1 })).toBe(1); + expect(render({ foo: true })).toBe(true); + expect(render({ foo: null })).toBe(null); + expect(render({ foo: undefined })).toBe(null); + expect(render({ foo: ["bar"] })).toEqual(["bar"]); + expect(render({ foo: [{ bar: "bar" }] })).toEqual([{ bar: "bar" }]); + expect(render({ foo: { prop1: "1" } })).toEqual({ prop1: "1" }); + expect( + render({ foo: { obj: { obj2: { num: 1, string: "str" } } } }) + ).toEqual({ obj: { obj2: { num: 1, string: "str" } } }); + expect( + render({ foo: { obj: { obj2: { num: 1, string: "str", bool: true } } } }) + ).toEqual({ obj: { obj2: { num: 1, string: "str", bool: true } } }); + }); + it("should return undefined", () => { + const json = { foo: "bar" }; + const input = "{{empty}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe('https://url.com'); - }); - it('should not escape \' in the middle of the string', () => { - const json = { foo: 'com' }; - const input = "{{\"https://'url.\" + 'test.' + .foo}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe(undefined); + }); + it("should return null on invalid json", () => { + const json = "foo"; + const input = "{{.foo}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe("https://'url.test.com"); - }); - it ('should run a jq function succesfully', () => { - const json = { foo: 'bar' }; - const input = '{{.foo | gsub("bar";"foo")}}'; - const result = jq.renderRecursively(json, input); + expect(result).toBe(null); + }); + it("should excape '' to \"\"", () => { + const json = { foo: "com" }; + const input = "{{'https://url.' + .foo}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe('foo'); - }); - it ('Testing multiple the \'\' in the same expression', () => { - const json = { foo: 'bar' }; - const input = "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe("https://url.com"); + }); + it("should not escape ' in the middle of the string", () => { + const json = { foo: "com" }; + const input = "{{\"https://'url.\" + 'test.' + .foo}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe('https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets'); - }); - it ('Testing multiple the \'\' in the same expression', () => { - const json = { foo: 'bar' }; - const input = "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe("https://'url.test.com"); + }); + it("should run a jq function succesfully", () => { + const json = { foo: "bar" }; + const input = '{{.foo | gsub("bar";"foo")}}'; + const result = jq.renderRecursively(json, input); - expect(result).toBe('https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets'); - }); - it('should break for invalid template', () => { - const json = { foo: 'bar' }; - const render = (input) => () => jq.renderRecursively(json, input); - - expect(render('prefix{{.foo}postfix')).toThrow('Found opening double braces in index 6 without closing double braces'); - expect(render('prefix{.foo}}postfix')).toThrow('Found closing double braces in index 11 without opening double braces'); - expect(render('prefix{{ .foo {{ }}postfix')).toThrow('Found double braces in index 14 inside other one in index 6'); - expect(render('prefix{{ .foo }} }}postfix')).toThrow('Found closing double braces in index 17 without opening double braces'); - expect(render('prefix{{ .foo }} }}postfix')).toThrow('Found closing double braces in index 17 without opening double braces'); - expect(render('prefix{{ "{{" + .foo }} }}postfix')).toThrow('Found closing double braces in index 24 without opening double braces'); - expect(render('prefix{{ \'{{\' + .foo }} }}postfix')).toThrow('Found closing double braces in index 24 without opening double braces'); - expect(render({'{{1}}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{1}}, evaluated to: 1'); - expect(render({'{{true}}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{true}}, evaluated to: true'); - expect(render({'{{ {} }}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{ {} }}, evaluated to: {}'); + expect(result).toBe("foo"); + }); + it("Testing multiple the '' in the same expression", () => { + const json = { foo: "bar" }; + const input = + "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; + const result = jq.renderRecursively(json, input); + + expect(result).toBe( + "https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets" + ); + }); + it("Testing multiple the '' in the same expression", () => { + const json = { foo: "bar" }; + const input = + "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; + const result = jq.renderRecursively(json, input); + + expect(result).toBe( + "https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets" + ); + }); + it("should break for invalid template", () => { + const json = { foo: "bar" }; + const render = (input) => () => jq.renderRecursively(json, input); + + expect(render("prefix{{.foo}postfix")).toThrow( + "Found opening double braces in index 6 without closing double braces" + ); + expect(render("prefix{.foo}}postfix")).toThrow( + "Found closing double braces in index 11 without opening double braces" + ); + expect(render("prefix{{ .foo {{ }}postfix")).toThrow( + "Found double braces in index 14 inside other one in index 6" + ); + expect(render("prefix{{ .foo }} }}postfix")).toThrow( + "Found closing double braces in index 17 without opening double braces" + ); + expect(render("prefix{{ .foo }} }}postfix")).toThrow( + "Found closing double braces in index 17 without opening double braces" + ); + expect(render('prefix{{ "{{" + .foo }} }}postfix')).toThrow( + "Found closing double braces in index 24 without opening double braces" + ); + expect(render("prefix{{ '{{' + .foo }} }}postfix")).toThrow( + "Found closing double braces in index 24 without opening double braces" + ); + expect(render({ "{{1}}": "bar" })).toThrow( + "Evaluated object key should be undefined, null or string. Original key: {{1}}, evaluated to: 1" + ); + expect(render({ "{{true}}": "bar" })).toThrow( + "Evaluated object key should be undefined, null or string. Original key: {{true}}, evaluated to: true" + ); + expect(render({ "{{ {} }}": "bar" })).toThrow( + "Evaluated object key should be undefined, null or string. Original key: {{ {} }}, evaluated to: {}" + ); + }); + it("should concat string and other types", () => { + const input = "https://some.random.url?q={{.foo}}"; + const render = (json) => jq.renderRecursively(json, input); + + expect(render({ foo: "bar" })).toBe("https://some.random.url?q=bar"); + expect(render({ foo: 1 })).toBe("https://some.random.url?q=1"); + expect(render({ foo: false })).toBe("https://some.random.url?q=false"); + expect(render({ foo: null })).toBe("https://some.random.url?q=null"); + expect(render({ foo: undefined })).toBe("https://some.random.url?q=null"); + expect(render({ foo: [1] })).toBe("https://some.random.url?q=[1]"); + expect(render({ foo: { bar: "bar" } })).toBe( + 'https://some.random.url?q={"bar":"bar"}' + ); + }); + it("testing multiple template blocks", () => { + const json = { + str: "bar", + num: 1, + bool: true, + null: null, + arr: ["foo"], + obj: { bar: "bar" }, + }; + const input = + "https://some.random.url?str={{.str}}&num={{.num}}&bool={{.bool}}&null={{.null}}&arr={{.arr}}&obj={{.obj}}"; + const result = jq.renderRecursively(json, input); + + expect(result).toBe( + 'https://some.random.url?str=bar&num=1&bool=true&null=null&arr=["foo"]&obj={"bar":"bar"}' + ); + }); + it("testing conditional key", () => { + const json = {}; + const render = (input) => jq.renderRecursively(json, input); + + expect(render({ "{{empty}}": "bar" })).toEqual({}); + expect(render({ "{{null}}": "bar" })).toEqual({}); + expect(render({ '{{""}}': "bar" })).toEqual({}); + expect(render({ "{{''}}": "bar" })).toEqual({}); + expect(render({ "{{ tempSpreadKeyword() }}": { foo: "bar" } })).toEqual({ + foo: "bar", }); - it('should concat string and other types', () => { - const input = 'https://some.random.url?q={{.foo}}'; - const render = (json) => jq.renderRecursively(json, input); - - expect(render({ foo: 'bar' })).toBe('https://some.random.url?q=bar'); - expect(render({ foo: 1 })).toBe('https://some.random.url?q=1'); - expect(render({ foo: false })).toBe('https://some.random.url?q=false'); - expect(render({ foo: null })).toBe('https://some.random.url?q=null'); - expect(render({ foo: undefined })).toBe('https://some.random.url?q=null'); - expect(render({ foo: [1] })).toBe('https://some.random.url?q=[1]'); - expect(render({ foo: {bar: 'bar'} })).toBe('https://some.random.url?q={\"bar\":\"bar\"}'); + expect(render({ "{{tempSpreadKeyword()}}": { foo: "bar" } })).toEqual({ + foo: "bar", }); - it('testing multiple template blocks', () => { - const json = {str: 'bar', num: 1, bool: true, 'null': null, arr: ['foo'], obj: {bar: 'bar'}}; - const input = 'https://some.random.url?str={{.str}}&num={{.num}}&bool={{.bool}}&null={{.null}}&arr={{.arr}}&obj={{.obj}}'; - const result = jq.renderRecursively(json, input); + }); + it("recursive templates should work", () => { + const json = { foo: "bar", bar: "foo" }; + const render = (input) => jq.renderRecursively(json, input); - expect(result).toBe("https://some.random.url?str=bar&num=1&bool=true&null=null&arr=[\"foo\"]&obj={\"bar\":\"bar\"}"); - }); - it('testing conditional key', () => { - const json = {}; - const render = (input) => jq.renderRecursively(json, input); - - expect(render({'{{empty}}': 'bar'})).toEqual({}); - expect(render({'{{null}}': 'bar'})).toEqual({}); - expect(render({'{{""}}': 'bar'})).toEqual({}); - expect(render({'{{\'\'}}': 'bar'})).toEqual({}); + expect(render({ "{{.foo}}": "{{.bar}}{{.foo}}" })).toEqual({ + bar: "foobar", }); - it('recursive templates should work', () => { - const json = { foo: 'bar', bar: 'foo' }; - const render = (input) => jq.renderRecursively(json, input); - - expect(render({'{{.foo}}': '{{.bar}}{{.foo}}'})).toEqual({bar: 'foobar'}); - expect(render({'{{.foo}}': {foo: '{{.foo}}'}})).toEqual({bar: {foo: 'bar'}}); - expect(render([1, true, null, undefined, '{{.foo}}', 'https://{{.bar}}.com'])).toEqual([1, true, null, undefined, 'bar', 'https://foo.com']); - expect(render([['{{.bar}}{{.foo}}'], 1, '{{.bar | ascii_upcase}}'])).toEqual([['foobar'], 1, 'FOO']); - expect(render([{'{{.bar}}': [false, '/foo/{{.foo + .bar}}']}])).toEqual([{foo: [false, '/foo/barfoo']}]); - expect(render({foo: [{bar: '{{1}}'}, '{{empty}}']})).toEqual({foo: [{bar: 1}, undefined]}); + expect(render({ "{{.foo}}": { foo: "{{.foo}}" } })).toEqual({ + bar: { foo: "bar" }, }); - it('should accept quotes outside of template', () => { - const json = { foo: 'bar', bar: 'foo' }; - const render = (input) => jq.renderRecursively(json, input); - - expect(render('"{{.foo}}"')).toEqual('"bar"'); - expect(render('\'{{.foo}}\'')).toEqual('\'bar\''); + expect( + render([1, true, null, undefined, "{{.foo}}", "https://{{.bar}}.com"]) + ).toEqual([1, true, null, undefined, "bar", "https://foo.com"]); + expect( + render([["{{.bar}}{{.foo}}"], 1, "{{.bar | ascii_upcase}}"]) + ).toEqual([["foobar"], 1, "FOO"]); + expect(render([{ "{{.bar}}": [false, "/foo/{{.foo + .bar}}"] }])).toEqual([ + { foo: [false, "/foo/barfoo"] }, + ]); + expect(render({ foo: [{ bar: "{{1}}" }, "{{empty}}"] })).toEqual({ + foo: [{ bar: 1 }, undefined], }); - it('should accept escaped quotes inside jq template', () => { - const json = { foo: 'bar', bar: 'foo' }; - const render = (input) => jq.renderRecursively(json, input); + }); + it("should accept quotes outside of template", () => { + const json = { foo: "bar", bar: "foo" }; + const render = (input) => jq.renderRecursively(json, input); - expect(render('{{"\\"foo\\""}}')).toEqual('"foo"'); - }); - it('test disable env', () => { - expect(jq.renderRecursively({}, '{{env}}', {enableEnv: false})).toEqual({}); - expect(jq.renderRecursively({}, '{{env}}', {enableEnv: true})).not.toEqual({}); - expect(jq.renderRecursively({}, '{{env}}', {})).toEqual({}); - expect(jq.renderRecursively({}, '{{env}}')).toEqual({}); - }) - it('test throw on error', () => { - expect(() => { jq.renderRecursively({}, '{{foo}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{1/0}}', {throwOnError: true}) }).toThrow("jq: compile error: Division by zero? at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{{}}', {throwOnError: true}) }).toThrow("jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{ {(0):1} }}', {throwOnError: true}) }).toThrow("jq: compile error: Cannot use number (0) as object key at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{if true then 1 else 0}}', {throwOnError: true}) }).toThrow("jq: compile error: Possibly unterminated 'if' statement at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{null | map(.+1)}}', {throwOnError: true}) }).toThrow("jq: error: Cannot iterate over null (null)"); - expect(() => { jq.renderRecursively({foo: "bar"}, '{{.foo + 1}}', {throwOnError: true}) }).toThrow("jq: error: string (\"bar\") and number (1) cannot be added"); - expect(() => { jq.renderRecursively({}, '{{foo}}/{{bar}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); - expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); - }) -}) + expect(render('"{{.foo}}"')).toEqual('"bar"'); + expect(render("'{{.foo}}'")).toEqual("'bar'"); + }); + it("should accept escaped quotes inside jq template", () => { + const json = { foo: "bar", bar: "foo" }; + const render = (input) => jq.renderRecursively(json, input); + expect(render('{{"\\"foo\\""}}')).toEqual('"foo"'); + }); + it("test disable env", () => { + expect(jq.renderRecursively({}, "{{env}}", { enableEnv: false })).toEqual( + {} + ); + expect( + jq.renderRecursively({}, "{{env}}", { enableEnv: true }) + ).not.toEqual({}); + expect(jq.renderRecursively({}, "{{env}}", {})).toEqual({}); + expect(jq.renderRecursively({}, "{{env}}")).toEqual({}); + }); + it("test throw on error", () => { + expect(() => { + jq.renderRecursively({}, "{{foo}}", { throwOnError: true }); + }).toThrow( + "jq: compile error: foo/0 is not defined at , line 1:" + ); + expect(() => { + jq.renderRecursively({}, "{{1/0}}", { throwOnError: true }); + }).toThrow("jq: compile error: Division by zero? at , line 1:"); + expect(() => { + jq.renderRecursively({}, "{{{}}", { throwOnError: true }); + }).toThrow( + "jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:" + ); + expect(() => { + jq.renderRecursively({}, "{{ {(0):1} }}", { throwOnError: true }); + }).toThrow( + "jq: compile error: Cannot use number (0) as object key at , line 1:" + ); + expect(() => { + jq.renderRecursively({}, "{{if true then 1 else 0}}", { + throwOnError: true, + }); + }).toThrow( + "jq: compile error: Possibly unterminated 'if' statement at , line 1:" + ); + expect(() => { + jq.renderRecursively({}, "{{null | map(.+1)}}", { throwOnError: true }); + }).toThrow("jq: error: Cannot iterate over null (null)"); + expect(() => { + jq.renderRecursively({ foo: "bar" }, "{{.foo + 1}}", { + throwOnError: true, + }); + }).toThrow('jq: error: string ("bar") and number (1) cannot be added'); + expect(() => { + jq.renderRecursively({}, "{{foo}}/{{bar}}", { throwOnError: true }); + }).toThrow( + "jq: compile error: foo/0 is not defined at , line 1:" + ); + expect(() => { + jq.renderRecursively({}, "/{{foo}}/", { throwOnError: true }); + }).toThrow( + "jq: compile error: foo/0 is not defined at , line 1:" + ); + expect(() => { + jq.renderRecursively( + {}, + { "{{ tempSpreadKeyword() }}": "str" }, + { throwOnError: true } + ); + }).toThrow( + 'Evaluated value should be an object if the key is {{ tempSpreadKeyword() }}. Original value: str, evaluated to: "str"' + ); + }); +}); From 2297f13fd9705106d5d5e024d8f0e0b19ea9fe6b Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Mon, 20 May 2024 17:44:21 +0300 Subject: [PATCH 02/12] revert formatting --- lib/template.js | 122 +++---------- test/template.test.js | 412 ++++++++++++++++-------------------------- 2 files changed, 182 insertions(+), 352 deletions(-) diff --git a/lib/template.js b/lib/template.js index 7b3331c..cf4016e 100644 --- a/lib/template.js +++ b/lib/template.js @@ -1,4 +1,4 @@ -const jq = require("./jq"); +const jq = require('./jq'); const findInsideDoubleBracesIndices = (input) => { let wrappingQuote = null; @@ -8,7 +8,7 @@ const findInsideDoubleBracesIndices = (input) => { for (let i = 0; i < input.length; i += 1) { const char = input[i]; - if (insideDoubleBracesStart && char === "\\") { + if (insideDoubleBracesStart && char === '\\') { // If next character is escaped, skip it i += 1; } @@ -19,62 +19,40 @@ const findInsideDoubleBracesIndices = (input) => { } else if (wrappingQuote === char) { wrappingQuote = null; } - } else if ( - !wrappingQuote && - char === "{" && - i > 0 && - input[i - 1] === "{" - ) { + } else if (!wrappingQuote && char === '{' && i > 0 && input[i - 1] === '{') { // if opening double braces that not wrapped with quotes if (insideDoubleBracesStart) { - throw new Error( - `Found double braces in index ${i - 1} inside other one in index ${ - insideDoubleBracesStart - "{{".length - }` - ); + throw new Error(`Found double braces in index ${i - 1} inside other one in index ${insideDoubleBracesStart - '{{'.length}`); } insideDoubleBracesStart = i + 1; - if (input[i + 1] === "{") { + if (input[i + 1] === '{') { // To overcome three "{" in a row considered as two different opening double braces i += 1; } - } else if ( - !wrappingQuote && - char === "}" && - i > 0 && - input[i - 1] === "}" - ) { + } else if (!wrappingQuote && char === '}' && i > 0 && input[i - 1] === '}') { // if closing double braces that not wrapped with quotes if (insideDoubleBracesStart) { - indices.push({ start: insideDoubleBracesStart, end: i - 1 }); + indices.push({start: insideDoubleBracesStart, end: i - 1}); insideDoubleBracesStart = null; - if (input[i + 1] === "}") { + if (input[i + 1] === '}') { // To overcome three "}" in a row considered as two different closing double braces i += 1; } } else { - throw new Error( - `Found closing double braces in index ${ - i - 1 - } without opening double braces` - ); + throw new Error(`Found closing double braces in index ${i - 1} without opening double braces`); } } } if (insideDoubleBracesStart) { - throw new Error( - `Found opening double braces in index ${ - insideDoubleBracesStart - "{{".length - } without closing double braces` - ); + throw new Error(`Found opening double braces in index ${insideDoubleBracesStart - '{{'.length} without closing double braces`); } return indices; -}; +} const render = (inputJson, template, execOptions = {}) => { - if (typeof template !== "string") { + if (typeof template !== 'string') { return null; } const indices = findInsideDoubleBracesIndices(template); @@ -84,93 +62,51 @@ const render = (inputJson, template, execOptions = {}) => { } const firstIndex = indices[0]; - if ( - indices.length === 1 && - template.trim().startsWith("{{") && - template.trim().endsWith("}}") - ) { + if (indices.length === 1 && template.trim().startsWith('{{') && template.trim().endsWith('}}')) { // If entire string is a template, evaluate and return the result with the original type - return jq.exec( - inputJson, - template.slice(firstIndex.start, firstIndex.end), - execOptions - ); + return jq.exec(inputJson, template.slice(firstIndex.start, firstIndex.end), execOptions); } - let result = template.slice(0, firstIndex.start - "{{".length); // Initiate result with string until first template start index + let result = template.slice(0, firstIndex.start - '{{'.length); // Initiate result with string until first template start index indices.forEach((index, i) => { - const jqResult = jq.exec( - inputJson, - template.slice(index.start, index.end), - execOptions - ); + const jqResult = jq.exec(inputJson, template.slice(index.start, index.end), execOptions); result += // Add to the result the stringified evaluated jq of the current template - (typeof jqResult === "string" ? jqResult : JSON.stringify(jqResult)) + + (typeof jqResult === 'string' ? jqResult : JSON.stringify(jqResult)) + // Add to the result from template end index. if last template index - until the end of string, else until next start index template.slice( - index.end + "}}".length, - i + 1 === indices.length - ? template.length - : indices[i + 1].start - "{{".length + index.end + '}}'.length, + i + 1 === indices.length ? template.length : indices[i + 1].start - '{{'.length, ); }); return result; -}; +} const renderRecursively = (inputJson, template, execOptions = {}) => { - if (typeof template === "string") { + if (typeof template === 'string') { return render(inputJson, template, execOptions); } if (Array.isArray(template)) { - return template.map((value) => - renderRecursively(inputJson, value, execOptions) - ); + return template.map((value) => renderRecursively(inputJson, value, execOptions)); } - if (typeof template === "object" && template !== null) { + if (typeof template === 'object' && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { - const MY_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; - const keywordMatcher = `\\{\\{\\s*${MY_KEYWORD_ESCAPED}\\s*\\}\\}`; - - if (key.match(keywordMatcher)) { - const evaluatedValue = renderRecursively( - inputJson, - value, - execOptions - ); - if (typeof evaluatedValue !== "object") { - throw new Error( - `Evaluated value should be an object if the key is ${key}. Original value: ${value}, evaluated to: ${JSON.stringify( - evaluatedValue - )}` - ); - } - return Object.entries(evaluatedValue); - } - const evaluatedKey = renderRecursively(inputJson, key, execOptions); - if ( - !["undefined", "string"].includes(typeof evaluatedKey) && - evaluatedKey !== null - ) { + if (!['undefined', 'string'].includes(typeof evaluatedKey) && evaluatedKey !== null) { throw new Error( - `Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify( - evaluatedKey - )}` + `Evaluated object key should be undefined, null or string. Original key: ${key}, evaluated to: ${JSON.stringify(evaluatedKey)}`, ); } - return evaluatedKey - ? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]] - : []; - }) + return evaluatedKey ? [[evaluatedKey, renderRecursively(inputJson, value, execOptions)]] : []; + }), ); } return template; -}; +} module.exports = { - renderRecursively, + renderRecursively }; diff --git a/test/template.test.js b/test/template.test.js index 337534c..69c7fee 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -1,276 +1,170 @@ -const jq = require("../lib"); +const jq = require('../lib'); -describe("template", () => { - it("should break", () => { - const json = { foo2: "bar" }; - const input = "{{.foo}}"; - const result = jq.renderRecursively(json, input); +describe('template', () => { + it('should break', () => { + const json = { foo2: 'bar' }; + const input = '{{.foo}}'; + const result = jq.renderRecursively(json, input); - expect(result).toBe(null); - }); - it("non template should work", () => { - const json = { foo2: "bar" }; - const render = (input) => jq.renderRecursively(json, input); - - expect(render(123)).toBe(123); - expect(render(undefined)).toBe(undefined); - expect(render(null)).toBe(null); - expect(render(true)).toBe(true); - expect(render(false)).toBe(false); - }); - it("different types should work", () => { - const input = "{{.foo}}"; - const render = (json) => jq.renderRecursively(json, input); - - expect(render({ foo: "bar" })).toBe("bar"); - expect(render({ foo: 1 })).toBe(1); - expect(render({ foo: true })).toBe(true); - expect(render({ foo: null })).toBe(null); - expect(render({ foo: undefined })).toBe(null); - expect(render({ foo: ["bar"] })).toEqual(["bar"]); - expect(render({ foo: [{ bar: "bar" }] })).toEqual([{ bar: "bar" }]); - expect(render({ foo: { prop1: "1" } })).toEqual({ prop1: "1" }); - expect( - render({ foo: { obj: { obj2: { num: 1, string: "str" } } } }) - ).toEqual({ obj: { obj2: { num: 1, string: "str" } } }); - expect( - render({ foo: { obj: { obj2: { num: 1, string: "str", bool: true } } } }) - ).toEqual({ obj: { obj2: { num: 1, string: "str", bool: true } } }); - }); - it("should return undefined", () => { - const json = { foo: "bar" }; - const input = "{{empty}}"; - const result = jq.renderRecursively(json, input); - - expect(result).toBe(undefined); - }); - it("should return null on invalid json", () => { - const json = "foo"; - const input = "{{.foo}}"; - const result = jq.renderRecursively(json, input); - - expect(result).toBe(null); - }); - it("should excape '' to \"\"", () => { - const json = { foo: "com" }; - const input = "{{'https://url.' + .foo}}"; - const result = jq.renderRecursively(json, input); - - expect(result).toBe("https://url.com"); - }); - it("should not escape ' in the middle of the string", () => { - const json = { foo: "com" }; - const input = "{{\"https://'url.\" + 'test.' + .foo}}"; - const result = jq.renderRecursively(json, input); - - expect(result).toBe("https://'url.test.com"); - }); - it("should run a jq function succesfully", () => { - const json = { foo: "bar" }; - const input = '{{.foo | gsub("bar";"foo")}}'; - const result = jq.renderRecursively(json, input); + expect(result).toBe(null); + }); + it('non template should work', () => { + const json = { foo2: 'bar' }; + const render = (input) => jq.renderRecursively(json, input); + + expect(render(123)).toBe(123); + expect(render(undefined)).toBe(undefined); + expect(render(null)).toBe(null); + expect(render(true)).toBe(true); + expect(render(false)).toBe(false); + }); + it('different types should work', () => { + const input = '{{.foo}}'; + const render = (json) => jq.renderRecursively(json, input); + + expect(render({ foo: 'bar' })).toBe('bar'); + expect(render({ foo: 1 })).toBe(1); + expect(render({ foo: true })).toBe(true); + expect(render({ foo: null })).toBe(null); + expect(render({ foo: undefined })).toBe(null); + expect(render({ foo: ['bar'] })).toEqual(['bar']); + expect(render({ foo: [{ bar: 'bar' }] })).toEqual([{ bar: 'bar' }]); + expect(render({ foo: {prop1: "1"} })).toEqual({prop1: "1"}); + expect(render({ foo: {obj: { obj2: { num: 1, string: "str"} }} })).toEqual({obj: { obj2: { num: 1, string: "str"} }}); + expect(render({ foo: { obj: { obj2: { num: 1, string: "str", bool: true} }} })).toEqual({ obj: { obj2: { num: 1, string: "str", bool: true} }}); + }); + it ('should return undefined', () => { + const json = { foo: 'bar' }; + const input = '{{empty}}'; + const result = jq.renderRecursively(json, input); - expect(result).toBe("foo"); - }); - it("Testing multiple the '' in the same expression", () => { - const json = { foo: "bar" }; - const input = - "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe(undefined); + }); + it ('should return null on invalid json', () => { + const json = "foo"; + const input = '{{.foo}}'; + const result = jq.renderRecursively(json, input); - expect(result).toBe( - "https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets" - ); - }); - it("Testing multiple the '' in the same expression", () => { - const json = { foo: "bar" }; - const input = - "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe(null); + }); + it('should excape \'\' to ""', () => { + const json = { foo: 'com' }; + const input = "{{'https://url.' + .foo}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe( - "https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets" - ); - }); - it("should break for invalid template", () => { - const json = { foo: "bar" }; - const render = (input) => () => jq.renderRecursively(json, input); + expect(result).toBe('https://url.com'); + }); + it('should not escape \' in the middle of the string', () => { + const json = { foo: 'com' }; + const input = "{{\"https://'url.\" + 'test.' + .foo}}"; + const result = jq.renderRecursively(json, input); - expect(render("prefix{{.foo}postfix")).toThrow( - "Found opening double braces in index 6 without closing double braces" - ); - expect(render("prefix{.foo}}postfix")).toThrow( - "Found closing double braces in index 11 without opening double braces" - ); - expect(render("prefix{{ .foo {{ }}postfix")).toThrow( - "Found double braces in index 14 inside other one in index 6" - ); - expect(render("prefix{{ .foo }} }}postfix")).toThrow( - "Found closing double braces in index 17 without opening double braces" - ); - expect(render("prefix{{ .foo }} }}postfix")).toThrow( - "Found closing double braces in index 17 without opening double braces" - ); - expect(render('prefix{{ "{{" + .foo }} }}postfix')).toThrow( - "Found closing double braces in index 24 without opening double braces" - ); - expect(render("prefix{{ '{{' + .foo }} }}postfix")).toThrow( - "Found closing double braces in index 24 without opening double braces" - ); - expect(render({ "{{1}}": "bar" })).toThrow( - "Evaluated object key should be undefined, null or string. Original key: {{1}}, evaluated to: 1" - ); - expect(render({ "{{true}}": "bar" })).toThrow( - "Evaluated object key should be undefined, null or string. Original key: {{true}}, evaluated to: true" - ); - expect(render({ "{{ {} }}": "bar" })).toThrow( - "Evaluated object key should be undefined, null or string. Original key: {{ {} }}, evaluated to: {}" - ); - }); - it("should concat string and other types", () => { - const input = "https://some.random.url?q={{.foo}}"; - const render = (json) => jq.renderRecursively(json, input); + expect(result).toBe("https://'url.test.com"); + }); + it ('should run a jq function succesfully', () => { + const json = { foo: 'bar' }; + const input = '{{.foo | gsub("bar";"foo")}}'; + const result = jq.renderRecursively(json, input); - expect(render({ foo: "bar" })).toBe("https://some.random.url?q=bar"); - expect(render({ foo: 1 })).toBe("https://some.random.url?q=1"); - expect(render({ foo: false })).toBe("https://some.random.url?q=false"); - expect(render({ foo: null })).toBe("https://some.random.url?q=null"); - expect(render({ foo: undefined })).toBe("https://some.random.url?q=null"); - expect(render({ foo: [1] })).toBe("https://some.random.url?q=[1]"); - expect(render({ foo: { bar: "bar" } })).toBe( - 'https://some.random.url?q={"bar":"bar"}' - ); - }); - it("testing multiple template blocks", () => { - const json = { - str: "bar", - num: 1, - bool: true, - null: null, - arr: ["foo"], - obj: { bar: "bar" }, - }; - const input = - "https://some.random.url?str={{.str}}&num={{.num}}&bool={{.bool}}&null={{.null}}&arr={{.arr}}&obj={{.obj}}"; - const result = jq.renderRecursively(json, input); + expect(result).toBe('foo'); + }); + it ('Testing multiple the \'\' in the same expression', () => { + const json = { foo: 'bar' }; + const input = "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; + const result = jq.renderRecursively(json, input); - expect(result).toBe( - 'https://some.random.url?str=bar&num=1&bool=true&null=null&arr=["foo"]&obj={"bar":"bar"}' - ); - }); - it("testing conditional key", () => { - const json = {}; - const render = (input) => jq.renderRecursively(json, input); + expect(result).toBe('https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets'); + }); + it ('Testing multiple the \'\' in the same expression', () => { + const json = { foo: 'bar' }; + const input = "{{'https://some.random.url' + .foo + '-1' + '.' + .foo + '.' + 'longgggg' + .foo + ')test(' + .foo + 'testadsftets'}}"; + const result = jq.renderRecursively(json, input); - expect(render({ "{{empty}}": "bar" })).toEqual({}); - expect(render({ "{{null}}": "bar" })).toEqual({}); - expect(render({ '{{""}}': "bar" })).toEqual({}); - expect(render({ "{{''}}": "bar" })).toEqual({}); - expect(render({ "{{ tempSpreadKeyword() }}": { foo: "bar" } })).toEqual({ - foo: "bar", + expect(result).toBe('https://some.random.urlbar-1.bar.longggggbar)test(bartestadsftets'); }); - expect(render({ "{{tempSpreadKeyword()}}": { foo: "bar" } })).toEqual({ - foo: "bar", + it('should break for invalid template', () => { + const json = { foo: 'bar' }; + const render = (input) => () => jq.renderRecursively(json, input); + + expect(render('prefix{{.foo}postfix')).toThrow('Found opening double braces in index 6 without closing double braces'); + expect(render('prefix{.foo}}postfix')).toThrow('Found closing double braces in index 11 without opening double braces'); + expect(render('prefix{{ .foo {{ }}postfix')).toThrow('Found double braces in index 14 inside other one in index 6'); + expect(render('prefix{{ .foo }} }}postfix')).toThrow('Found closing double braces in index 17 without opening double braces'); + expect(render('prefix{{ .foo }} }}postfix')).toThrow('Found closing double braces in index 17 without opening double braces'); + expect(render('prefix{{ "{{" + .foo }} }}postfix')).toThrow('Found closing double braces in index 24 without opening double braces'); + expect(render('prefix{{ \'{{\' + .foo }} }}postfix')).toThrow('Found closing double braces in index 24 without opening double braces'); + expect(render({'{{1}}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{1}}, evaluated to: 1'); + expect(render({'{{true}}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{true}}, evaluated to: true'); + expect(render({'{{ {} }}': 'bar'})).toThrow('Evaluated object key should be undefined, null or string. Original key: {{ {} }}, evaluated to: {}'); }); - }); - it("recursive templates should work", () => { - const json = { foo: "bar", bar: "foo" }; - const render = (input) => jq.renderRecursively(json, input); + it('should concat string and other types', () => { + const input = 'https://some.random.url?q={{.foo}}'; + const render = (json) => jq.renderRecursively(json, input); + + expect(render({ foo: 'bar' })).toBe('https://some.random.url?q=bar'); + expect(render({ foo: 1 })).toBe('https://some.random.url?q=1'); + expect(render({ foo: false })).toBe('https://some.random.url?q=false'); + expect(render({ foo: null })).toBe('https://some.random.url?q=null'); + expect(render({ foo: undefined })).toBe('https://some.random.url?q=null'); + expect(render({ foo: [1] })).toBe('https://some.random.url?q=[1]'); + expect(render({ foo: {bar: 'bar'} })).toBe('https://some.random.url?q={\"bar\":\"bar\"}'); + }); + it('testing multiple template blocks', () => { + const json = {str: 'bar', num: 1, bool: true, 'null': null, arr: ['foo'], obj: {bar: 'bar'}}; + const input = 'https://some.random.url?str={{.str}}&num={{.num}}&bool={{.bool}}&null={{.null}}&arr={{.arr}}&obj={{.obj}}'; + const result = jq.renderRecursively(json, input); - expect(render({ "{{.foo}}": "{{.bar}}{{.foo}}" })).toEqual({ - bar: "foobar", + expect(result).toBe("https://some.random.url?str=bar&num=1&bool=true&null=null&arr=[\"foo\"]&obj={\"bar\":\"bar\"}"); + }); + it('testing conditional key', () => { + const json = {}; + const render = (input) => jq.renderRecursively(json, input); + + expect(render({'{{empty}}': 'bar'})).toEqual({}); + expect(render({'{{null}}': 'bar'})).toEqual({}); + expect(render({'{{""}}': 'bar'})).toEqual({}); + expect(render({'{{\'\'}}': 'bar'})).toEqual({}); }); - expect(render({ "{{.foo}}": { foo: "{{.foo}}" } })).toEqual({ - bar: { foo: "bar" }, + it('recursive templates should work', () => { + const json = { foo: 'bar', bar: 'foo' }; + const render = (input) => jq.renderRecursively(json, input); + + expect(render({'{{.foo}}': '{{.bar}}{{.foo}}'})).toEqual({bar: 'foobar'}); + expect(render({'{{.foo}}': {foo: '{{.foo}}'}})).toEqual({bar: {foo: 'bar'}}); + expect(render([1, true, null, undefined, '{{.foo}}', 'https://{{.bar}}.com'])).toEqual([1, true, null, undefined, 'bar', 'https://foo.com']); + expect(render([['{{.bar}}{{.foo}}'], 1, '{{.bar | ascii_upcase}}'])).toEqual([['foobar'], 1, 'FOO']); + expect(render([{'{{.bar}}': [false, '/foo/{{.foo + .bar}}']}])).toEqual([{foo: [false, '/foo/barfoo']}]); + expect(render({foo: [{bar: '{{1}}'}, '{{empty}}']})).toEqual({foo: [{bar: 1}, undefined]}); }); - expect( - render([1, true, null, undefined, "{{.foo}}", "https://{{.bar}}.com"]) - ).toEqual([1, true, null, undefined, "bar", "https://foo.com"]); - expect( - render([["{{.bar}}{{.foo}}"], 1, "{{.bar | ascii_upcase}}"]) - ).toEqual([["foobar"], 1, "FOO"]); - expect(render([{ "{{.bar}}": [false, "/foo/{{.foo + .bar}}"] }])).toEqual([ - { foo: [false, "/foo/barfoo"] }, - ]); - expect(render({ foo: [{ bar: "{{1}}" }, "{{empty}}"] })).toEqual({ - foo: [{ bar: 1 }, undefined], + it('should accept quotes outside of template', () => { + const json = { foo: 'bar', bar: 'foo' }; + const render = (input) => jq.renderRecursively(json, input); + + expect(render('"{{.foo}}"')).toEqual('"bar"'); + expect(render('\'{{.foo}}\'')).toEqual('\'bar\''); }); - }); - it("should accept quotes outside of template", () => { - const json = { foo: "bar", bar: "foo" }; - const render = (input) => jq.renderRecursively(json, input); + it('should accept escaped quotes inside jq template', () => { + const json = { foo: 'bar', bar: 'foo' }; + const render = (input) => jq.renderRecursively(json, input); - expect(render('"{{.foo}}"')).toEqual('"bar"'); - expect(render("'{{.foo}}'")).toEqual("'bar'"); - }); - it("should accept escaped quotes inside jq template", () => { - const json = { foo: "bar", bar: "foo" }; - const render = (input) => jq.renderRecursively(json, input); + expect(render('{{"\\"foo\\""}}')).toEqual('"foo"'); + }); + it('test disable env', () => { + expect(jq.renderRecursively({}, '{{env}}', {enableEnv: false})).toEqual({}); + expect(jq.renderRecursively({}, '{{env}}', {enableEnv: true})).not.toEqual({}); + expect(jq.renderRecursively({}, '{{env}}', {})).toEqual({}); + expect(jq.renderRecursively({}, '{{env}}')).toEqual({}); + }) + it('test throw on error', () => { + expect(() => { jq.renderRecursively({}, '{{foo}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); + expect(() => { jq.renderRecursively({}, '{{1/0}}', {throwOnError: true}) }).toThrow("jq: compile error: Division by zero? at , line 1:"); + expect(() => { jq.renderRecursively({}, '{{{}}', {throwOnError: true}) }).toThrow("jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:"); + expect(() => { jq.renderRecursively({}, '{{ {(0):1} }}', {throwOnError: true}) }).toThrow("jq: compile error: Cannot use number (0) as object key at , line 1:"); + expect(() => { jq.renderRecursively({}, '{{if true then 1 else 0}}', {throwOnError: true}) }).toThrow("jq: compile error: Possibly unterminated 'if' statement at , line 1:"); + expect(() => { jq.renderRecursively({}, '{{null | map(.+1)}}', {throwOnError: true}) }).toThrow("jq: error: Cannot iterate over null (null)"); + expect(() => { jq.renderRecursively({foo: "bar"}, '{{.foo + 1}}', {throwOnError: true}) }).toThrow("jq: error: string (\"bar\") and number (1) cannot be added"); + expect(() => { jq.renderRecursively({}, '{{foo}}/{{bar}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); + expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); + }) +}) - expect(render('{{"\\"foo\\""}}')).toEqual('"foo"'); - }); - it("test disable env", () => { - expect(jq.renderRecursively({}, "{{env}}", { enableEnv: false })).toEqual( - {} - ); - expect( - jq.renderRecursively({}, "{{env}}", { enableEnv: true }) - ).not.toEqual({}); - expect(jq.renderRecursively({}, "{{env}}", {})).toEqual({}); - expect(jq.renderRecursively({}, "{{env}}")).toEqual({}); - }); - it("test throw on error", () => { - expect(() => { - jq.renderRecursively({}, "{{foo}}", { throwOnError: true }); - }).toThrow( - "jq: compile error: foo/0 is not defined at , line 1:" - ); - expect(() => { - jq.renderRecursively({}, "{{1/0}}", { throwOnError: true }); - }).toThrow("jq: compile error: Division by zero? at , line 1:"); - expect(() => { - jq.renderRecursively({}, "{{{}}", { throwOnError: true }); - }).toThrow( - "jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:" - ); - expect(() => { - jq.renderRecursively({}, "{{ {(0):1} }}", { throwOnError: true }); - }).toThrow( - "jq: compile error: Cannot use number (0) as object key at , line 1:" - ); - expect(() => { - jq.renderRecursively({}, "{{if true then 1 else 0}}", { - throwOnError: true, - }); - }).toThrow( - "jq: compile error: Possibly unterminated 'if' statement at , line 1:" - ); - expect(() => { - jq.renderRecursively({}, "{{null | map(.+1)}}", { throwOnError: true }); - }).toThrow("jq: error: Cannot iterate over null (null)"); - expect(() => { - jq.renderRecursively({ foo: "bar" }, "{{.foo + 1}}", { - throwOnError: true, - }); - }).toThrow('jq: error: string ("bar") and number (1) cannot be added'); - expect(() => { - jq.renderRecursively({}, "{{foo}}/{{bar}}", { throwOnError: true }); - }).toThrow( - "jq: compile error: foo/0 is not defined at , line 1:" - ); - expect(() => { - jq.renderRecursively({}, "/{{foo}}/", { throwOnError: true }); - }).toThrow( - "jq: compile error: foo/0 is not defined at , line 1:" - ); - expect(() => { - jq.renderRecursively( - {}, - { "{{ tempSpreadKeyword() }}": "str" }, - { throwOnError: true } - ); - }).toThrow( - 'Evaluated value should be an object if the key is {{ tempSpreadKeyword() }}. Original value: str, evaluated to: "str"' - ); - }); -}); From a8244cb98d84a8b16d446f2b45cc39cbc1a2c2c1 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Mon, 20 May 2024 17:49:57 +0300 Subject: [PATCH 03/12] returned the spread keyword implementation --- lib/template.js | 13 +++++++++++++ test/template.test.js | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/lib/template.js b/lib/template.js index cf4016e..049a910 100644 --- a/lib/template.js +++ b/lib/template.js @@ -93,6 +93,19 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { if (typeof template === 'object' && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { + const MY_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; + const keywordMatcher = `^\\{\\{\\s*${MY_KEYWORD_ESCAPED}\\s*\\}\\}$`; + + if (key.match(keywordMatcher)) { + const evaluatedValue = renderRecursively(inputJson, value, execOptions); + if (typeof evaluatedValue !== "object") { + throw new Error( + `Evaluated value should be an object if the key is ${key}. Original value: ${value}, evaluated to: ${JSON.stringify(evaluatedValue)}` + ); + } + return Object.entries(evaluatedValue); + } + const evaluatedKey = renderRecursively(inputJson, key, execOptions); if (!['undefined', 'string'].includes(typeof evaluatedKey) && evaluatedKey !== null) { throw new Error( diff --git a/test/template.test.js b/test/template.test.js index 69c7fee..acd7edd 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -124,6 +124,8 @@ describe('template', () => { expect(render({'{{null}}': 'bar'})).toEqual({}); expect(render({'{{""}}': 'bar'})).toEqual({}); expect(render({'{{\'\'}}': 'bar'})).toEqual({}); + expect(render({ "{{tempSpreadKeyword()}}": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ "{{ tempSpreadKeyword() }}": { foo: "bar" } })).toEqual({foo: "bar"}); }); it('recursive templates should work', () => { const json = { foo: 'bar', bar: 'foo' }; @@ -165,6 +167,8 @@ describe('template', () => { expect(() => { jq.renderRecursively({foo: "bar"}, '{{.foo + 1}}', {throwOnError: true}) }).toThrow("jq: error: string (\"bar\") and number (1) cannot be added"); expect(() => { jq.renderRecursively({}, '{{foo}}/{{bar}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); + expect(() => { jq.renderRecursively({}, { "{{ tempSpreadKeyword() }}": "str" }, { throwOnError: true }) }) + .toThrow('Evaluated value should be an object if the key is {{ tempSpreadKeyword() }}. Original value: str, evaluated to: "str"'); }) }) From a98157577e1ab9c15d2f7f3802af0698cc7ef636 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Tue, 21 May 2024 08:39:27 +0300 Subject: [PATCH 04/12] renamed variable --- lib/template.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template.js b/lib/template.js index 049a910..c857415 100644 --- a/lib/template.js +++ b/lib/template.js @@ -93,8 +93,8 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { if (typeof template === 'object' && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { - const MY_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; - const keywordMatcher = `^\\{\\{\\s*${MY_KEYWORD_ESCAPED}\\s*\\}\\}$`; + const TEMP_SPREAD_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; + const keywordMatcher = `^\\{\\{\\s*${TEMP_SPREAD_KEYWORD_ESCAPED}\\s*\\}\\}$`; if (key.match(keywordMatcher)) { const evaluatedValue = renderRecursively(inputJson, value, execOptions); From d02e74cba0055ac01cd59a55e2a84f1c20b617de Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Tue, 21 May 2024 09:02:52 +0300 Subject: [PATCH 05/12] cleaned the keyword definition --- lib/template.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template.js b/lib/template.js index c857415..1aeafa8 100644 --- a/lib/template.js +++ b/lib/template.js @@ -93,8 +93,8 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { if (typeof template === 'object' && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { - const TEMP_SPREAD_KEYWORD_ESCAPED = "tempSpreadKeyword\\(\\)"; - const keywordMatcher = `^\\{\\{\\s*${TEMP_SPREAD_KEYWORD_ESCAPED}\\s*\\}\\}$`; + const SPREAD_KEYWORD = "tempSpreadKeyword"; + const keywordMatcher = `^\\{\\{\\s*${SPREAD_KEYWORD}\\(\s*\\)\\s*\\}\\}$`; // matches {{ () }} with white spaces where you'd expect them if (key.match(keywordMatcher)) { const evaluatedValue = renderRecursively(inputJson, value, execOptions); From 38a56589924f2e91ad8360d1c0018ebf6960f8a4 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Tue, 21 May 2024 12:47:48 +0300 Subject: [PATCH 06/12] renamed the spreadOperator --- lib/template.js | 2 +- test/template.test.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/template.js b/lib/template.js index 1aeafa8..59c948d 100644 --- a/lib/template.js +++ b/lib/template.js @@ -93,7 +93,7 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { if (typeof template === 'object' && template !== null) { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { - const SPREAD_KEYWORD = "tempSpreadKeyword"; + const SPREAD_KEYWORD = "spreadValue"; const keywordMatcher = `^\\{\\{\\s*${SPREAD_KEYWORD}\\(\s*\\)\\s*\\}\\}$`; // matches {{ () }} with white spaces where you'd expect them if (key.match(keywordMatcher)) { diff --git a/test/template.test.js b/test/template.test.js index acd7edd..3bb9d1c 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -124,8 +124,8 @@ describe('template', () => { expect(render({'{{null}}': 'bar'})).toEqual({}); expect(render({'{{""}}': 'bar'})).toEqual({}); expect(render({'{{\'\'}}': 'bar'})).toEqual({}); - expect(render({ "{{tempSpreadKeyword()}}": { foo: "bar" } })).toEqual({foo: "bar"}); - expect(render({ "{{ tempSpreadKeyword() }}": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ "{{spreadValue()}}": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ "{{ spreadValue() }}": { foo: "bar" } })).toEqual({foo: "bar"}); }); it('recursive templates should work', () => { const json = { foo: 'bar', bar: 'foo' }; @@ -167,8 +167,8 @@ describe('template', () => { expect(() => { jq.renderRecursively({foo: "bar"}, '{{.foo + 1}}', {throwOnError: true}) }).toThrow("jq: error: string (\"bar\") and number (1) cannot be added"); expect(() => { jq.renderRecursively({}, '{{foo}}/{{bar}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); - expect(() => { jq.renderRecursively({}, { "{{ tempSpreadKeyword() }}": "str" }, { throwOnError: true }) }) - .toThrow('Evaluated value should be an object if the key is {{ tempSpreadKeyword() }}. Original value: str, evaluated to: "str"'); + expect(() => { jq.renderRecursively({}, { "{{ spreadValue() }}": "str" }, { throwOnError: true }) }) + .toThrow('Evaluated value should be an object if the key is {{ spreadValue() }}. Original value: str, evaluated to: "str"'); }) }) From 414109699b4024ad6fe7ee0cd9fd3a6c13e694ec Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Tue, 21 May 2024 15:02:27 +0300 Subject: [PATCH 07/12] added whitespace support --- lib/template.js | 2 +- test/template.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template.js b/lib/template.js index 59c948d..909065a 100644 --- a/lib/template.js +++ b/lib/template.js @@ -96,7 +96,7 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { const SPREAD_KEYWORD = "spreadValue"; const keywordMatcher = `^\\{\\{\\s*${SPREAD_KEYWORD}\\(\s*\\)\\s*\\}\\}$`; // matches {{ () }} with white spaces where you'd expect them - if (key.match(keywordMatcher)) { + if (key.trim().match(keywordMatcher)) { const evaluatedValue = renderRecursively(inputJson, value, execOptions); if (typeof evaluatedValue !== "object") { throw new Error( diff --git a/test/template.test.js b/test/template.test.js index 3bb9d1c..3892022 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -125,7 +125,7 @@ describe('template', () => { expect(render({'{{""}}': 'bar'})).toEqual({}); expect(render({'{{\'\'}}': 'bar'})).toEqual({}); expect(render({ "{{spreadValue()}}": { foo: "bar" } })).toEqual({foo: "bar"}); - expect(render({ "{{ spreadValue() }}": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ " {{ spreadValue() }} ": { foo: "bar" } })).toEqual({foo: "bar"}); }); it('recursive templates should work', () => { const json = { foo: 'bar', bar: 'foo' }; From 9bd5ac537955d22422a7cf9ae2f36c5a7ea5134c Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Tue, 21 May 2024 15:44:39 +0300 Subject: [PATCH 08/12] fixed whitespace handling and added tests --- lib/template.js | 4 ++-- test/template.test.js | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/template.js b/lib/template.js index 909065a..265fd1e 100644 --- a/lib/template.js +++ b/lib/template.js @@ -94,9 +94,9 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { const SPREAD_KEYWORD = "spreadValue"; - const keywordMatcher = `^\\{\\{\\s*${SPREAD_KEYWORD}\\(\s*\\)\\s*\\}\\}$`; // matches {{ () }} with white spaces where you'd expect them + const keywordMatcher = `^\\s*\\{\\{\\s*${SPREAD_KEYWORD}\\(\\s*\\)\\s*\\}\\}\\s*$`; // matches {{ () }} with white spaces where you'd expect them - if (key.trim().match(keywordMatcher)) { + if (key.match(keywordMatcher)) { const evaluatedValue = renderRecursively(inputJson, value, execOptions); if (typeof evaluatedValue !== "object") { throw new Error( diff --git a/test/template.test.js b/test/template.test.js index 3892022..085624c 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -125,7 +125,8 @@ describe('template', () => { expect(render({'{{""}}': 'bar'})).toEqual({}); expect(render({'{{\'\'}}': 'bar'})).toEqual({}); expect(render({ "{{spreadValue()}}": { foo: "bar" } })).toEqual({foo: "bar"}); - expect(render({ " {{ spreadValue() }} ": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ " {{ spreadValue( ) }} ": { foo: "bar" } })).toEqual({foo: "bar"}); + expect(render({ "{{spreadValue()}}": "{{ {foo: \"bar\"} }}" })).toEqual({ foo: "bar" }); }); it('recursive templates should work', () => { const json = { foo: 'bar', bar: 'foo' }; @@ -169,6 +170,8 @@ describe('template', () => { expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); expect(() => { jq.renderRecursively({}, { "{{ spreadValue() }}": "str" }, { throwOnError: true }) }) .toThrow('Evaluated value should be an object if the key is {{ spreadValue() }}. Original value: str, evaluated to: "str"'); + expect(() => { jq.renderRecursively({}, { "{{ spreadValue() }}": "{{ \"str\" }}" }, { throwOnError: true }) }) + .toThrow('Evaluated value should be an object if the key is {{ spreadValue() }}. Original value: {{ \"str\" }}, evaluated to: "str"'); }) }) From 60b748845e5e5519acc178fe1b177b6caf881b97 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Wed, 22 May 2024 13:15:49 +0300 Subject: [PATCH 09/12] updated test --- test/template.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/template.test.js b/test/template.test.js index 085624c..445eabe 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -117,7 +117,7 @@ describe('template', () => { expect(result).toBe("https://some.random.url?str=bar&num=1&bool=true&null=null&arr=[\"foo\"]&obj={\"bar\":\"bar\"}"); }); it('testing conditional key', () => { - const json = {}; + const json = { foo: "bar" }; const render = (input) => jq.renderRecursively(json, input); expect(render({'{{empty}}': 'bar'})).toEqual({}); @@ -126,7 +126,7 @@ describe('template', () => { expect(render({'{{\'\'}}': 'bar'})).toEqual({}); expect(render({ "{{spreadValue()}}": { foo: "bar" } })).toEqual({foo: "bar"}); expect(render({ " {{ spreadValue( ) }} ": { foo: "bar" } })).toEqual({foo: "bar"}); - expect(render({ "{{spreadValue()}}": "{{ {foo: \"bar\"} }}" })).toEqual({ foo: "bar" }); + expect(render({ "{{spreadValue()}}": "{{ . }}" })).toEqual({ foo: "bar" }); }); it('recursive templates should work', () => { const json = { foo: 'bar', bar: 'foo' }; From 116ecb6bff3cc250a910bfc792dab70f4bca961e Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Wed, 22 May 2024 13:19:26 +0300 Subject: [PATCH 10/12] changed regex to expect a trimmed input --- lib/template.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/template.js b/lib/template.js index 265fd1e..6c62c73 100644 --- a/lib/template.js +++ b/lib/template.js @@ -94,9 +94,9 @@ const renderRecursively = (inputJson, template, execOptions = {}) => { return Object.fromEntries( Object.entries(template).flatMap(([key, value]) => { const SPREAD_KEYWORD = "spreadValue"; - const keywordMatcher = `^\\s*\\{\\{\\s*${SPREAD_KEYWORD}\\(\\s*\\)\\s*\\}\\}\\s*$`; // matches {{ () }} with white spaces where you'd expect them + const keywordMatcher = `^\\{\\{\\s*${SPREAD_KEYWORD}\\(\\s*\\)\\s*\\}\\}$`; // matches {{ () }} with white spaces where you'd expect them - if (key.match(keywordMatcher)) { + if (key.trim().match(keywordMatcher)) { const evaluatedValue = renderRecursively(inputJson, value, execOptions); if (typeof evaluatedValue !== "object") { throw new Error( From 2e43454bfcec1aaed24afe63d3da600f02ccd220 Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Wed, 22 May 2024 13:21:47 +0300 Subject: [PATCH 11/12] split test cases to separate its --- test/template.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/template.test.js b/test/template.test.js index 445eabe..6478a0d 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -117,13 +117,18 @@ describe('template', () => { expect(result).toBe("https://some.random.url?str=bar&num=1&bool=true&null=null&arr=[\"foo\"]&obj={\"bar\":\"bar\"}"); }); it('testing conditional key', () => { - const json = { foo: "bar" }; + const json = {}; const render = (input) => jq.renderRecursively(json, input); expect(render({'{{empty}}': 'bar'})).toEqual({}); expect(render({'{{null}}': 'bar'})).toEqual({}); expect(render({'{{""}}': 'bar'})).toEqual({}); expect(render({'{{\'\'}}': 'bar'})).toEqual({}); + }); + it('testing spread key', () => { + const json = { foo: "bar" }; + const render = (input) => jq.renderRecursively(json, input); + expect(render({ "{{spreadValue()}}": { foo: "bar" } })).toEqual({foo: "bar"}); expect(render({ " {{ spreadValue( ) }} ": { foo: "bar" } })).toEqual({foo: "bar"}); expect(render({ "{{spreadValue()}}": "{{ . }}" })).toEqual({ foo: "bar" }); From 3b86451a167da221eac5ead8b6a3218e7afaac1c Mon Sep 17 00:00:00 2001 From: Paz Hershberg Date: Wed, 22 May 2024 13:25:33 +0300 Subject: [PATCH 12/12] updated version --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index b590a7c..773bfb5 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.12", + "version": "v0.0.13", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.12", + "version": "v0.0.13", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index cd941e5..7feb013 100755 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.12", + "version": "v0.0.13", "description": "Node.js bindings for JQ", - "jq-node-bindings": "0.0.12", + "jq-node-bindings": "0.0.13", "main": "lib/index.js", "scripts": { "configure": "node-gyp configure",