Skip to content

Commit

Permalink
Merge pull request #11 from port-labs/PORT-5841-add-jq-errors2
Browse files Browse the repository at this point in the history
Add class exceptions
  • Loading branch information
talsabagport authored Jan 24, 2024
2 parents a90b3d5 + 9e9cd0f commit 844daf1
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 22 deletions.
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -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<any> | string | number | boolean | null;

export function renderRecursively(json: object, input: object | Array<any> | string | number | boolean | null, execOptions?: ExecOptions): object | Array<any> | string | number | boolean | null;
Expand Down
4 changes: 3 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
14 changes: 12 additions & 2 deletions lib/jq.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@ 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}))

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
};
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
6 changes: 3 additions & 3 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void jv_object_to_v8(std::string key, jv actual, v8::Local<v8::Object> 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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions test/santiy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <top-level>, line 1:");
expect(() => { jq.exec({}, '1/0', {throwOnError: true}) }).toThrow("jq: error: Division by zero? at <top-level>, line 1:");
expect(() => { jq.exec({}, '{', {throwOnError: true}) }).toThrow("jq: error: syntax error, unexpected $end (Unix shell quoting issues?) at <top-level>, line 1:");
expect(() => { jq.exec({}, '{(0):1}', {throwOnError: true}) }).toThrow("jq: error: Cannot use number (0) as object key at <top-level>, line 1:");
expect(() => { jq.exec({}, 'if true then 1 else 0', {throwOnError: true}) }).toThrow("jq: error: Possibly unterminated 'if' statement at <top-level>, line 1:");
expect(() => { jq.exec({}, 'foo', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at <top-level>, line 1:");
expect(() => { jq.exec({}, '1/0', {throwOnError: true}) }).toThrow("jq: compile error: Division by zero? at <top-level>, line 1:");
expect(() => { jq.exec({}, '{', {throwOnError: true}) }).toThrow("jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at <top-level>, line 1:");
expect(() => { jq.exec({}, '{(0):1}', {throwOnError: true}) }).toThrow("jq: compile error: Cannot use number (0) as object key at <top-level>, line 1:");
expect(() => { jq.exec({}, 'if true then 1 else 0', {throwOnError: true}) }).toThrow("jq: compile error: Possibly unterminated 'if' statement at <top-level>, 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");
})
Expand Down
14 changes: 7 additions & 7 deletions test/template.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{1/0}}', {throwOnError: true}) }).toThrow("jq: error: Division by zero? at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{{}}', {throwOnError: true}) }).toThrow("jq: error: syntax error, unexpected $end (Unix shell quoting issues?) at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{ {(0):1} }}', {throwOnError: true}) }).toThrow("jq: error: Cannot use number (0) as object key at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{if true then 1 else 0}}', {throwOnError: true}) }).toThrow("jq: error: Possibly unterminated 'if' statement at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{foo}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{1/0}}', {throwOnError: true}) }).toThrow("jq: compile error: Division by zero? at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{{}}', {throwOnError: true}) }).toThrow("jq: compile error: syntax error, unexpected $end (Unix shell quoting issues?) at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{ {(0):1} }}', {throwOnError: true}) }).toThrow("jq: compile error: Cannot use number (0) as object key at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{if true then 1 else 0}}', {throwOnError: true}) }).toThrow("jq: compile error: Possibly unterminated 'if' statement at <top-level>, 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 <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: error: foo/0 is not defined at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '{{foo}}/{{bar}}', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at <top-level>, line 1:");
expect(() => { jq.renderRecursively({}, '/{{foo}}/', {throwOnError: true}) }).toThrow("jq: compile error: foo/0 is not defined at <top-level>, line 1:");
})
})

0 comments on commit 844daf1

Please sign in to comment.