[njs] Introduced AggregateError implementation.

Alexander Borisov alexander.borisov at nginx.com
Wed Aug 11 18:49:51 UTC 2021


details:   https://hg.nginx.org/njs/rev/ca2f051a4fc9
branches:  
changeset: 1684:ca2f051a4fc9
user:      Alexander Borisov <alexander.borisov at nginx.com>
date:      Wed Aug 11 21:48:51 2021 +0300
description:
Introduced AggregateError implementation.

diffstat:

 src/njs_builtin.c        |   11 ++++
 src/njs_error.c          |  127 +++++++++++++++++++++++++++++++++++++++++++++-
 src/njs_error.h          |    4 +-
 src/njs_fs.c             |    2 +-
 src/njs_iterator.c       |   45 ++++++++++++++++
 src/njs_iterator.h       |    2 +
 src/njs_object_hash.h    |   29 ++++++++++
 src/njs_vm.h             |    1 +
 src/test/njs_unit_test.c |   20 +++++++
 9 files changed, 234 insertions(+), 7 deletions(-)

diffs (407 lines):

diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_builtin.c
--- a/src/njs_builtin.c	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_builtin.c	Wed Aug 11 21:48:51 2021 +0300
@@ -114,6 +114,7 @@ static const njs_object_type_init_t *con
     &njs_type_error_type_init,
     &njs_uri_error_type_init,
     &njs_memory_error_type_init,
+    &njs_aggregate_error_type_init,
 };
 
 
@@ -1676,6 +1677,16 @@ static const njs_object_prop_t  njs_glob
         .writable = 1,
         .configurable = 1,
     },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("AggregateError"),
+        .value = njs_prop_handler2(njs_top_level_constructor,
+                                   NJS_OBJ_TYPE_AGGREGATE_ERROR,
+                                   NJS_AGGREGATE_ERROR_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
 };
 
 
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_error.c
--- a/src/njs_error.c	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_error.c	Wed Aug 11 21:48:51 2021 +0300
@@ -24,6 +24,7 @@ static njs_int_t njs_backtrace_to_string
 static const njs_value_t  njs_error_message_string = njs_string("message");
 static const njs_value_t  njs_error_name_string = njs_string("name");
 static const njs_value_t  njs_error_stack_string = njs_string("stack");
+static const njs_value_t  njs_error_errors_string = njs_string("errors");
 
 
 void
@@ -45,7 +46,7 @@ njs_error_new(njs_vm_t *vm, njs_value_t 
         return;
     }
 
-    error = njs_error_alloc(vm, type, NULL, &string);
+    error = njs_error_alloc(vm, type, NULL, &string, NULL);
     if (njs_slow_path(error == NULL)) {
         return;
     }
@@ -198,7 +199,7 @@ njs_error_stack(njs_vm_t *vm, njs_value_
 
 njs_object_t *
 njs_error_alloc(njs_vm_t *vm, njs_object_type_t type, const njs_value_t *name,
-    const njs_value_t *message)
+    const njs_value_t *message, const njs_value_t *errors)
 {
     njs_int_t           ret;
     njs_object_t        *error;
@@ -262,6 +263,26 @@ njs_error_alloc(njs_vm_t *vm, njs_object
         }
     }
 
+    if (errors != NULL) {
+        lhq.key = njs_str_value("errors");
+        lhq.key_hash = NJS_ERRORS_HASH;
+
+        prop = njs_object_prop_alloc(vm, &njs_error_errors_string, errors, 1);
+        if (njs_slow_path(prop == NULL)) {
+            goto memory_error;
+        }
+
+        prop->enumerable = 0;
+
+        lhq.value = prop;
+
+        ret = njs_lvlhsh_insert(&error->hash, &lhq);
+        if (njs_slow_path(ret != NJS_OK)) {
+            njs_internal_error(vm, "lvlhsh insert failed");
+            return NULL;
+        }
+    }
+
     return error;
 
 memory_error:
@@ -277,10 +298,32 @@ njs_error_constructor(njs_vm_t *vm, njs_
     njs_index_t type)
 {
     njs_int_t     ret;
-    njs_value_t   *value;
+    njs_value_t   *iterator, *value, list;
+    njs_array_t   *array;
     njs_object_t  *error;
 
-    value = njs_arg(args, nargs, 1);
+    if (type != NJS_OBJ_TYPE_AGGREGATE_ERROR) {
+        iterator = NULL;
+        value = njs_arg(args, nargs, 1);
+
+        njs_set_undefined(&list);
+
+    } else {
+        iterator = njs_arg(args, nargs, 1);
+        value = njs_arg(args, nargs, 2);
+
+        if (njs_slow_path(iterator->type < NJS_STRING)) {
+            njs_type_error(vm, "first argument is not iterable");
+            return NJS_ERROR;
+        }
+
+        array = njs_iterator_to_array(vm, iterator);
+        if (njs_slow_path(array == NULL)) {
+            return NJS_ERROR;
+        }
+
+        njs_set_array(&list, array);
+    }
 
     if (njs_slow_path(!njs_is_string(value))) {
         if (!njs_is_undefined(value)) {
@@ -292,7 +335,8 @@ njs_error_constructor(njs_vm_t *vm, njs_
     }
 
     error = njs_error_alloc(vm, type, NULL,
-                            njs_is_defined(value) ? value : NULL);
+                            njs_is_defined(value) ? value : NULL,
+                            njs_is_defined(&list) ? &list : NULL);
     if (njs_slow_path(error == NULL)) {
         return NJS_ERROR;
     }
@@ -543,6 +587,36 @@ const njs_object_init_t  njs_uri_error_c
 };
 
 
+static const njs_object_prop_t  njs_aggregate_error_constructor_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("AggregateError"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 1.0),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_object_prototype_create),
+    },
+};
+
+
+const njs_object_init_t  njs_aggregate_error_constructor_init = {
+    njs_aggregate_error_constructor_properties,
+    njs_nitems(njs_aggregate_error_constructor_properties),
+};
+
+
 void
 njs_memory_error_set(njs_vm_t *vm, njs_value_t *value)
 {
@@ -1164,6 +1238,49 @@ const njs_object_type_init_t  njs_uri_er
 };
 
 
+static const njs_object_prop_t  njs_aggregate_error_prototype_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("AggregateError"),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("message"),
+        .value = njs_string(""),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("constructor"),
+        .value = njs_prop_handler(njs_object_prototype_create_constructor),
+        .writable = 1,
+        .configurable = 1,
+    },
+};
+
+
+const njs_object_init_t  njs_aggregate_error_prototype_init = {
+    njs_aggregate_error_prototype_properties,
+    njs_nitems(njs_aggregate_error_prototype_properties),
+};
+
+
+const njs_object_type_init_t  njs_aggregate_error_type_init = {
+    .constructor = njs_native_ctor(njs_error_constructor, 1,
+                                   NJS_OBJ_TYPE_AGGREGATE_ERROR),
+    .constructor_props = &njs_aggregate_error_constructor_init,
+    .prototype_props = &njs_aggregate_error_prototype_init,
+    .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
 static njs_int_t
 njs_add_backtrace_entry(njs_vm_t *vm, njs_arr_t *stack,
     njs_native_frame_t *native_frame)
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_error.h
--- a/src/njs_error.h	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_error.h	Wed Aug 11 21:48:51 2021 +0300
@@ -41,7 +41,8 @@ void njs_memory_error(njs_vm_t *vm);
 void njs_memory_error_set(njs_vm_t *vm, njs_value_t *value);
 
 njs_object_t *njs_error_alloc(njs_vm_t *vm, njs_object_type_t type,
-    const njs_value_t *name, const njs_value_t *message);
+    const njs_value_t *name, const njs_value_t *message,
+    const njs_value_t *errors);
 njs_int_t njs_error_to_string(njs_vm_t *vm, njs_value_t *retval,
     const njs_value_t *error);
 njs_int_t njs_error_stack(njs_vm_t *vm, njs_value_t *value, njs_value_t *stack);
@@ -57,6 +58,7 @@ extern const njs_object_type_init_t  njs
 extern const njs_object_type_init_t  njs_type_error_type_init;
 extern const njs_object_type_init_t  njs_uri_error_type_init;
 extern const njs_object_type_init_t  njs_memory_error_type_init;
+extern const njs_object_type_init_t  njs_aggregate_error_type_init;
 
 
 njs_inline njs_int_t
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_fs.c
--- a/src/njs_fs.c	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_fs.c	Wed Aug 11 21:48:51 2021 +0300
@@ -1491,7 +1491,7 @@ njs_fs_error(njs_vm_t *vm, const char *s
         return NJS_ERROR;
     }
 
-    error = njs_error_alloc(vm, NJS_OBJ_TYPE_ERROR, NULL, &value);
+    error = njs_error_alloc(vm, NJS_OBJ_TYPE_ERROR, NULL, &value, NULL);
     if (njs_slow_path(error == NULL)) {
         return NJS_ERROR;
     }
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_iterator.c
--- a/src/njs_iterator.c	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_iterator.c	Wed Aug 11 21:48:51 2021 +0300
@@ -26,6 +26,9 @@ static njs_int_t njs_iterator_object_han
     njs_iterator_handler_t handler, njs_iterator_args_t *args,
     njs_value_t *key, int64_t i);
 
+static njs_int_t njs_iterator_to_array_handler(njs_vm_t *vm,
+    njs_iterator_args_t *args, njs_value_t *value, int64_t index);
+
 
 njs_int_t
 njs_array_iterator_create(njs_vm_t *vm, const njs_value_t *target,
@@ -676,3 +679,45 @@ njs_iterator_object_handler(njs_vm_t *vm
 
     return ret;
 }
+
+
+njs_array_t *
+njs_iterator_to_array(njs_vm_t *vm, njs_value_t *iterator)
+{
+    int64_t              length;
+    njs_int_t            ret;
+    njs_iterator_args_t  args;
+
+    njs_memzero(&args, sizeof(njs_iterator_args_t));
+
+    ret = njs_object_length(vm, iterator, &length);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
+
+    args.array = njs_array_alloc(vm, 1, length, 0);
+    if (njs_slow_path(args.array == NULL)) {
+        return NULL;
+    }
+
+    args.value = iterator;
+    args.to = length;
+
+    ret = njs_object_iterate(vm, &args, njs_iterator_to_array_handler);
+    if (njs_slow_path(ret == NJS_ERROR)) {
+        njs_mp_free(vm->mem_pool, args.array);
+        return NULL;
+    }
+
+    return args.array;
+}
+
+
+static njs_int_t
+njs_iterator_to_array_handler(njs_vm_t *vm, njs_iterator_args_t *args,
+    njs_value_t *value, int64_t index)
+{
+    args->array->start[index] = *value;
+
+    return NJS_OK;
+}
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_iterator.h
--- a/src/njs_iterator.h	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_iterator.h	Wed Aug 11 21:48:51 2021 +0300
@@ -36,6 +36,8 @@ njs_int_t njs_object_iterate(njs_vm_t *v
 njs_int_t njs_object_iterate_reverse(njs_vm_t *vm, njs_iterator_args_t *args,
     njs_iterator_handler_t handler);
 
+njs_array_t *njs_iterator_to_array(njs_vm_t *vm, njs_value_t *iterator);
+
 
 extern const njs_object_type_init_t  njs_iterator_type_init;
 extern const njs_object_type_init_t  njs_array_iterator_type_init;
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_object_hash.h
--- a/src/njs_object_hash.h	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_object_hash.h	Wed Aug 11 21:48:51 2021 +0300
@@ -343,6 +343,25 @@
         'E'), 'r'), 'r'), 'o'), 'r')
 
 
+#define NJS_AGGREGATE_ERROR_HASH                                              \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'A'), 'g'), 'g'), 'r'), 'e'), 'g'), 'a'), 't'), 'e'),                 \
+        'E'), 'r'), 'r'), 'o'), 'r')
+
+
 #define NJS_MESSAGE_HASH                                                      \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
@@ -354,6 +373,16 @@
         'm'), 'e'), 's'), 's'), 'a'), 'g'), 'e')
 
 
+#define NJS_ERRORS_HASH                                                       \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'e'), 'r'), 'r'), 'o'), 'r'), 's')
+
+
 #define NJS_MODE_HASH                                                         \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/njs_vm.h
--- a/src/njs_vm.h	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/njs_vm.h	Wed Aug 11 21:48:51 2021 +0300
@@ -86,6 +86,7 @@ typedef enum {
     NJS_OBJ_TYPE_TYPE_ERROR,
     NJS_OBJ_TYPE_URI_ERROR,
     NJS_OBJ_TYPE_MEMORY_ERROR,
+    NJS_OBJ_TYPE_AGGREGATE_ERROR,
 
     NJS_OBJ_TYPE_MAX,
 } njs_object_type_t;
diff -r eb6c1c9823f1 -r ca2f051a4fc9 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed Aug 11 21:48:50 2021 +0300
+++ b/src/test/njs_unit_test.c	Wed Aug 11 21:48:51 2021 +0300
@@ -11134,6 +11134,26 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var e = RangeError('e'); Object.preventExtensions(e);e"),
       njs_str("RangeError: e") },
 
+    /* AggregateError. */
+
+    { njs_str("AggregateError()"),
+      njs_str("TypeError: first argument is not iterable") },
+
+    { njs_str("AggregateError([1, 2, 3])"),
+      njs_str("AggregateError") },
+
+    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e.message"),
+      njs_str("m") },
+
+    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e.errors"),
+      njs_str("1,2,3") },
+
+    { njs_str("let e = AggregateError('abc'); e.errors"),
+      njs_str("a,b,c") },
+
+    { njs_str("let e = AggregateError([1, 2, 3], 'm'); e"),
+      njs_str("AggregateError: m") },
+
     /* Memory object is immutable. */
 
     { njs_str("var e = MemoryError('e'); e.name = 'E'"),


More information about the nginx-devel mailing list