From 9e9cd0f19ea6e9d3b51de7fc71ef9bb5a193ed1b Mon Sep 17 00:00:00 2001 From: talsabagport Date: Wed, 24 Jan 2024 16:55:34 +0200 Subject: [PATCH] Add class exceptions --- index.d.ts | 6 ++++++ lib/index.js | 4 +++- lib/jq.js | 14 ++++++++++++-- package-lock.json | 4 ++-- package.json | 4 ++-- src/binding.cc | 6 +++--- test/santiy.test.js | 10 +++++----- test/template.test.js | 14 +++++++------- 8 files changed, 40 insertions(+), 22 deletions(-) diff --git a/index.d.ts b/index.d.ts index a37e9ee..a4bb966 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,6 +1,12 @@ declare module '@port-labs/jq-node-bindings' { type ExecOptions = { enableEnv?: boolean, throwOnError?: boolean }; + export class JqExecError extends Error { + } + + export class JqExecCompileError extends Error { + } + export function exec(json: object, input: string, options?: ExecOptions): object | Array | string | number | boolean | null; export function renderRecursively(json: object, input: object | Array | string | number | boolean | null, execOptions?: ExecOptions): object | Array | string | number | boolean | null; diff --git a/lib/index.js b/lib/index.js index 9080512..41d308c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,5 +4,7 @@ const template = require('./template'); module.exports = { exec: jq.exec, - renderRecursively: template.renderRecursively + renderRecursively: template.renderRecursively, + JqExecError: jq.JqExecError, + JqExecCompileError: jq.JqExecCompileError, }; diff --git a/lib/jq.js b/lib/jq.js index f399ff7..bcfb2ae 100644 --- a/lib/jq.js +++ b/lib/jq.js @@ -6,6 +6,14 @@ const formatFilter = (filter, {enableEnv = false} = {}) => { // Conditionally enable access to env return enableEnv ? formattedFilter : `def env: {}; {} as $ENV | ${formattedFilter}`; } + + +class JqExecError extends Error { +} + +class JqExecCompileError extends JqExecError { +} + const exec = (object, filter, {enableEnv = false, throwOnError = false} = {}) => { try { const data = nativeJq.exec(JSON.stringify(object), formatFilter(filter, {enableEnv})) @@ -13,12 +21,14 @@ const exec = (object, filter, {enableEnv = false, throwOnError = false} = {}) => return data?.value; } catch (err) { if (throwOnError) { - throw err; + throw new (err?.message?.startsWith('jq: compile error') ? JqExecCompileError : JqExecError)(err.message); } return null } } module.exports = { - exec + exec, + JqExecError, + JqExecCompileError }; diff --git a/package-lock.json b/package-lock.json index a0d3e12..b590a7c 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.11", + "version": "v0.0.12", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.11", + "version": "v0.0.12", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3ee972b..cd941e5 100755 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "@port-labs/jq-node-bindings", - "version": "v0.0.11", + "version": "v0.0.12", "description": "Node.js bindings for JQ", - "jq-node-bindings": "0.0.11", + "jq-node-bindings": "0.0.12", "main": "lib/index.js", "scripts": { "configure": "node-gyp configure", diff --git a/src/binding.cc b/src/binding.cc index 764086a..f71dd0c 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -63,7 +63,7 @@ void jv_object_to_v8(std::string key, jv actual, v8::Local ret) { snprintf(err, sizeof(err), "jq: error: %s", jv_string_value(msg)); jv_free(msg); jv_free(actual); - Nan::ThrowTypeError(err); + Nan::ThrowError(err); return; } jv_free(msg); @@ -127,7 +127,7 @@ void throw_err_cb(void *data, jv msg) { if (jv_get_kind(msg) != JV_KIND_STRING) msg = jv_dump_string(msg, JV_PRINT_INVALID); if (!strncmp(jv_string_value(msg), "jq: error", sizeof("jq: error") - 1)) - snprintf(err_data->buf, sizeof(err_data->buf), "%s", jv_string_value(msg)); + snprintf(err_data->buf, sizeof(err_data->buf), "jq: compile error%s", jv_string_value(msg) + strlen("jq: error")); if (strchr(err_data->buf, '\n')) *(strchr(err_data->buf, '\n')) = '\0'; jv_free(msg); @@ -143,7 +143,7 @@ void jq_exec(std::string json, std::string filter,const Nan::FunctionCallbackInf jq = jq_init(); jq_set_error_cb(jq, throw_err_cb, &err_msg); if (!jq_compile(jq, filter.c_str())) { - Nan::ThrowTypeError(err_msg.buf); + Nan::ThrowError(err_msg.buf); return; } cache.put(filter, jq); diff --git a/test/santiy.test.js b/test/santiy.test.js index 238c4eb..8ecbb04 100644 --- a/test/santiy.test.js +++ b/test/santiy.test.js @@ -159,11 +159,11 @@ describe('jq', () => { }) it('test throw on error', () => { - expect(() => { jq.exec({}, 'foo', {throwOnError: true}) }).toThrow("jq: error: foo/0 is not defined at , line 1:"); - expect(() => { jq.exec({}, '1/0', {throwOnError: true}) }).toThrow("jq: error: Division by zero? at , line 1:"); - expect(() => { jq.exec({}, '{', {throwOnError: true}) }).toThrow("jq: error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:"); - expect(() => { jq.exec({}, '{(0):1}', {throwOnError: true}) }).toThrow("jq: error: Cannot use number (0) as object key at , line 1:"); - expect(() => { jq.exec({}, 'if true then 1 else 0', {throwOnError: true}) }).toThrow("jq: error: Possibly unterminated 'if' statement at , line 1:"); + expect(() => { jq.exec({}, 'foo', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at , line 1:"); + expect(() => { jq.exec({}, '1/0', {throwOnError: true}) }).toThrow("jq: compile error: Division by zero? at , line 1:"); + expect(() => { jq.exec({}, '{', {throwOnError: true}) }).toThrow("jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:"); + expect(() => { jq.exec({}, '{(0):1}', {throwOnError: true}) }).toThrow("jq: compile error: Cannot use number (0) as object key at , line 1:"); + expect(() => { jq.exec({}, 'if true then 1 else 0', {throwOnError: true}) }).toThrow("jq: compile error: Possibly unterminated 'if' statement at , line 1:"); expect(() => { jq.exec({}, 'null | map(.+1)', {throwOnError: true}) }).toThrow("jq: error: Cannot iterate over null (null)"); expect(() => { jq.exec({foo: "bar"}, '.foo + 1', {throwOnError: true}) }).toThrow("jq: error: string (\"bar\") and number (1) cannot be added"); }) diff --git a/test/template.test.js b/test/template.test.js index c94baa3..69c7fee 100644 --- a/test/template.test.js +++ b/test/template.test.js @@ -156,15 +156,15 @@ describe('template', () => { expect(jq.renderRecursively({}, '{{env}}')).toEqual({}); }) it('test throw on error', () => { - expect(() => { jq.renderRecursively({}, '{{foo}}', {throwOnError: true}) }).toThrow("jq: error: foo/0 is not defined at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{1/0}}', {throwOnError: true}) }).toThrow("jq: error: Division by zero? at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{{}}', {throwOnError: true}) }).toThrow("jq: error: syntax error, unexpected $end (Unix shell quoting issues?) at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{ {(0):1} }}', {throwOnError: true}) }).toThrow("jq: error: Cannot use number (0) as object key at , line 1:"); - expect(() => { jq.renderRecursively({}, '{{if true then 1 else 0}}', {throwOnError: true}) }).toThrow("jq: error: Possibly unterminated 'if' statement at , line 1:"); + 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: error: foo/0 is not defined at , line 1:"); - expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: error: foo/0 is not defined at , line 1:"); + 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:"); }) })