GeezerVison is showing github.com — n-api: add napi_get_all_property_names · nodejs/node@0911813
File treeExpand file treeCollapse file tree Open diff view settings test/js-native-api/test_object
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/n-api.md +91Lines changed: 91 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1660,6 +1660,66 @@ However, for better performance, it's better for the caller to make sure that | 1660 | 1660 | the `napi_value` in question is of the JavaScript type expected by the API. | 1661 | 1661 |
| 1662 | 1662 | ### Enum types | | 1663 | +#### napi_key_collection_mode | | 1664 | +<!-- YAML | | 1665 | +added: REPLACEME | | 1666 | +--> | | 1667 | + | | 1668 | +> Stability: 1 - Experimental | | 1669 | + | | 1670 | +```C | | 1671 | +typedef enum { | | 1672 | + napi_key_include_prototypes, | | 1673 | + napi_key_own_only | | 1674 | +} napi_key_collection_mode; | | 1675 | +``` | | 1676 | + | | 1677 | +Describes the `Keys/Properties` filter enums: | | 1678 | + | | 1679 | +`napi_key_collection_mode` limits the range of collected properties. | | 1680 | + | | 1681 | +`napi_key_own_only` limits the collected properties to the given | | 1682 | +object only. `napi_key_include_prototypes` will include all keys | | 1683 | +of the objects's prototype chain as well. | | 1684 | + | | 1685 | +#### napi_key_filter | | 1686 | +<!-- YAML | | 1687 | +added: REPLACEME | | 1688 | +--> | | 1689 | + | | 1690 | +> Stability: 1 - Experimental | | 1691 | + | | 1692 | +```C | | 1693 | +typedef enum { | | 1694 | + napi_key_all_properties = 0, | | 1695 | + napi_key_writable = 1, | | 1696 | + napi_key_enumerable = 1 << 1, | | 1697 | + napi_key_configurable = 1 << 2, | | 1698 | + napi_key_skip_strings = 1 << 3, | | 1699 | + napi_key_skip_symbols = 1 << 4 | | 1700 | +} napi_key_filter; | | 1701 | +``` | | 1702 | + | | 1703 | +Property filter bits. They can be or'ed to build a composite filter. | | 1704 | + | | 1705 | +#### napi_key_conversion | | 1706 | +<!-- YAML | | 1707 | +added: REPLACEME | | 1708 | +--> | | 1709 | + | | 1710 | +> Stability: 1 - Experimental | | 1711 | + | | 1712 | +```C | | 1713 | +typedef enum { | | 1714 | + napi_key_keep_numbers, | | 1715 | + napi_key_numbers_to_strings | | 1716 | +} napi_key_conversion; | | 1717 | +``` | | 1718 | + | | 1719 | +`napi_key_numbers_to_strings` will convert integer indices to | | 1720 | +strings. `napi_key_keep_numbers` will return numbers for integer | | 1721 | +indices. | | 1722 | + | 1663 | 1723 | #### napi_valuetype | 1664 | 1724 |
| 1665 | 1725 | ```C | @@ -3532,6 +3592,37 @@ This API returns the names of the enumerable properties of `object` as an array | 3532 | 3592 | of strings. The properties of `object` whose key is a symbol will not be | 3533 | 3593 | included. | 3534 | 3594 |
| | 3595 | +#### napi_get_all_property_names | | 3596 | +<!-- YAML | | 3597 | +added: REPLACEME | | 3598 | +--> | | 3599 | + | | 3600 | +> Stability: 1 - Experimental | | 3601 | + | | 3602 | +```C | | 3603 | +napi_get_all_property_names(napi_env env, | | 3604 | + napi_value object, | | 3605 | + napi_key_collection_mode key_mode, | | 3606 | + napi_key_filter key_filter, | | 3607 | + napi_key_conversion key_conversion, | | 3608 | + napi_value* result); | | 3609 | +``` | | 3610 | + | | 3611 | +* `[in] env`: The environment that the N-API call is invoked under. | | 3612 | +* `[in] object`: The object from which to retrieve the properties. | | 3613 | +* `[in] key_mode`: Whether to retrieve prototype properties as well. | | 3614 | +* `[in] key_filter`: Which properties to retrieve | | 3615 | +(enumerable/readable/writable). | | 3616 | +* `[in] key_conversion`: Whether to convert numbered property keys to strings. | | 3617 | +* `[out] result`: A `napi_value` representing an array of JavaScript values | | 3618 | +that represent the property names of the object. [`napi_get_array_length`][] and | | 3619 | +[`napi_get_element`][] can be used to iterate over `result`. | | 3620 | + | | 3621 | +Returns `napi_ok` if the API succeeded. | | 3622 | + | | 3623 | +This API returns an array containing the names of the available properties | | 3624 | +of this object. | | 3625 | + | 3535 | 3626 | #### napi_set_property | 3536 | 3627 | <!-- YAML | 3537 | 3628 | added: v8.0.0 | |
Collapse file Copy file name to clipboardExpand all lines: src/js_native_api.h +9Lines changed: 9 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -506,6 +506,15 @@ NAPI_EXTERN napi_status napi_get_value_bigint_words(napi_env env, | 506 | 506 | size_t* word_count, | 507 | 507 | uint64_t* words); | 508 | 508 |
| | 509 | +// Object | | 510 | +NAPI_EXTERN napi_status | | 511 | +napi_get_all_property_names(napi_env env, | | 512 | + napi_value object, | | 513 | + napi_key_collection_mode key_mode, | | 514 | + napi_key_filter key_filter, | | 515 | + napi_key_conversion key_conversion, | | 516 | + napi_value* result); | | 517 | + | 509 | 518 | // Instance data | 510 | 519 | NAPI_EXTERN napi_status napi_set_instance_data(napi_env env, | 511 | 520 | void* data, | |
Collapse file Copy file name to clipboardExpand all lines: src/js_native_api_types.h +21Lines changed: 21 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -115,4 +115,25 @@ typedef struct { | 115 | 115 | napi_status error_code; | 116 | 116 | } napi_extended_error_info; | 117 | 117 |
| | 118 | +#ifdef NAPI_EXPERIMENTAL | | 119 | +typedef enum { | | 120 | + napi_key_include_prototypes, | | 121 | + napi_key_own_only | | 122 | +} napi_key_collection_mode; | | 123 | + | | 124 | +typedef enum { | | 125 | + napi_key_all_properties = 0, | | 126 | + napi_key_writable = 1, | | 127 | + napi_key_enumerable = 1 << 1, | | 128 | + napi_key_configurable = 1 << 2, | | 129 | + napi_key_skip_strings = 1 << 3, | | 130 | + napi_key_skip_symbols = 1 << 4 | | 131 | +} napi_key_filter; | | 132 | + | | 133 | +typedef enum { | | 134 | + napi_key_keep_numbers, | | 135 | + napi_key_numbers_to_strings | | 136 | +} napi_key_conversion; | | 137 | +#endif | | 138 | + | 118 | 139 | #endif // SRC_JS_NATIVE_API_TYPES_H_ |
Collapse file Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc +77-11Lines changed: 77 additions & 11 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -898,26 +898,92 @@ napi_status napi_define_class(napi_env env, | 898 | 898 | napi_status napi_get_property_names(napi_env env, | 899 | 899 | napi_value object, | 900 | 900 | napi_value* result) { | | 901 | + return napi_get_all_property_names( | | 902 | + env, | | 903 | + object, | | 904 | + napi_key_include_prototypes, | | 905 | + static_cast<napi_key_filter>(napi_key_enumerable | | | 906 | + napi_key_skip_symbols), | | 907 | + napi_key_numbers_to_strings, | | 908 | + result); | | 909 | +} | | 910 | + | | 911 | +napi_status napi_get_all_property_names(napi_env env, | | 912 | + napi_value object, | | 913 | + napi_key_collection_mode key_mode, | | 914 | + napi_key_filter key_filter, | | 915 | + napi_key_conversion key_conversion, | | 916 | + napi_value* result) { | 901 | 917 | NAPI_PREAMBLE(env); | 902 | 918 | CHECK_ARG(env, result); | 903 | 919 |
| 904 | 920 | v8::Local<v8::Context> context = env->context(); | 905 | 921 | v8::Local<v8::Object> obj; | 906 | 922 | CHECK_TO_OBJECT(env, context, obj, object); | 907 | 923 |
| 908 | | - v8::MaybeLocal<v8::Array> maybe_propertynames = obj->GetPropertyNames( | 909 | | - context, | 910 | | - v8::KeyCollectionMode::kIncludePrototypes, | 911 | | - static_cast<v8::PropertyFilter>( | 912 | | - v8::PropertyFilter::ONLY_ENUMERABLE | | 913 | | - v8::PropertyFilter::SKIP_SYMBOLS), | 914 | | - v8::IndexFilter::kIncludeIndices, | 915 | | - v8::KeyConversionMode::kConvertToString); | | 924 | + v8::PropertyFilter filter = v8::PropertyFilter::ALL_PROPERTIES; | | 925 | + if (key_filter & napi_key_writable) { | | 926 | + filter = | | 927 | + static_cast<v8::PropertyFilter>(filter | | | 928 | + v8::PropertyFilter::ONLY_WRITABLE); | | 929 | + } | | 930 | + if (key_filter & napi_key_enumerable) { | | 931 | + filter = | | 932 | + static_cast<v8::PropertyFilter>(filter | | | 933 | + v8::PropertyFilter::ONLY_ENUMERABLE); | | 934 | + } | | 935 | + if (key_filter & napi_key_configurable) { | | 936 | + filter = | | 937 | + static_cast<v8::PropertyFilter>(filter | | | 938 | + v8::PropertyFilter::ONLY_WRITABLE); | | 939 | + } | | 940 | + if (key_filter & napi_key_skip_strings) { | | 941 | + filter = | | 942 | + static_cast<v8::PropertyFilter>(filter | | | 943 | + v8::PropertyFilter::SKIP_STRINGS); | | 944 | + } | | 945 | + if (key_filter & napi_key_skip_symbols) { | | 946 | + filter = | | 947 | + static_cast<v8::PropertyFilter>(filter | | | 948 | + v8::PropertyFilter::SKIP_SYMBOLS); | | 949 | + } | | 950 | + v8::KeyCollectionMode collection_mode; | | 951 | + v8::KeyConversionMode conversion_mode; | | 952 | + | | 953 | + switch (key_mode) { | | 954 | + case napi_key_include_prototypes: | | 955 | + collection_mode = v8::KeyCollectionMode::kIncludePrototypes; | | 956 | + break; | | 957 | + case napi_key_own_only: | | 958 | + collection_mode = v8::KeyCollectionMode::kOwnOnly; | | 959 | + break; | | 960 | + default: | | 961 | + return napi_set_last_error(env, napi_invalid_arg); | | 962 | + } | 916 | 963 |
| 917 | | - CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure); | | 964 | + switch (key_conversion) { | | 965 | + case napi_key_keep_numbers: | | 966 | + conversion_mode = v8::KeyConversionMode::kKeepNumbers; | | 967 | + break; | | 968 | + case napi_key_numbers_to_strings: | | 969 | + conversion_mode = v8::KeyConversionMode::kConvertToString; | | 970 | + break; | | 971 | + default: | | 972 | + return napi_set_last_error(env, napi_invalid_arg); | | 973 | + } | 918 | 974 |
| 919 | | - *result = v8impl::JsValueFromV8LocalValue( | 920 | | - maybe_propertynames.ToLocalChecked()); | | 975 | + v8::MaybeLocal<v8::Array> maybe_all_propertynames = | | 976 | + obj->GetPropertyNames(context, | | 977 | + collection_mode, | | 978 | + filter, | | 979 | + v8::IndexFilter::kIncludeIndices, | | 980 | + conversion_mode); | | 981 | + | | 982 | + CHECK_MAYBE_EMPTY_WITH_PREAMBLE( | | 983 | + env, maybe_all_propertynames, napi_generic_failure); | | 984 | + | | 985 | + *result = | | 986 | + v8impl::JsValueFromV8LocalValue(maybe_all_propertynames.ToLocalChecked()); | 921 | 987 | return GET_RETURN_STATUS(env); | 922 | 988 | } | 923 | 989 |
| |
Collapse file Copy file name to clipboardExpand all lines: src/js_native_api_v8.h +11Lines changed: 11 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -165,6 +165,17 @@ napi_status napi_set_last_error(napi_env env, napi_status error_code, | 165 | 165 | } \ | 166 | 166 | } while (0) | 167 | 167 |
| | 168 | +#define RETURN_STATUS_IF_FALSE_WITH_PREAMBLE(env, condition, status) \ | | 169 | + do { \ | | 170 | + if (!(condition)) { \ | | 171 | + return napi_set_last_error( \ | | 172 | + (env), try_catch.HasCaught() ? napi_pending_exception : (status)); \ | | 173 | + } \ | | 174 | + } while (0) | | 175 | + | | 176 | +#define CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, maybe, status) \ | | 177 | + RETURN_STATUS_IF_FALSE_WITH_PREAMBLE((env), !((maybe).IsEmpty()), (status)) | | 178 | + | 168 | 179 | namespace v8impl { | 169 | 180 |
| 170 | 181 | //=== Conversion between V8 Handles and napi_value ======================== | |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test.js +6-1Lines changed: 6 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -212,8 +212,10 @@ assert.strictEqual(newObject.test_string, 'test string'); | 212 | 212 | inherited: 1 | 213 | 213 | }); | 214 | 214 |
| | 215 | + const fooSymbol = Symbol('foo'); | | 216 | + | 215 | 217 | object.normal = 2; | 216 | | - object[Symbol('foo')] = 3; | | 218 | + object[fooSymbol] = 3; | 217 | 219 | Object.defineProperty(object, 'unenumerable', { | 218 | 220 | value: 4, | 219 | 221 | enumerable: false, | @@ -224,6 +226,9 @@ assert.strictEqual(newObject.test_string, 'test string'); | 224 | 226 |
| 225 | 227 | assert.deepStrictEqual(test_object.GetPropertyNames(object), | 226 | 228 | ['5', 'normal', 'inherited']); | | 229 | + | | 230 | + assert.deepStrictEqual(test_object.GetSymbolNames(object), | | 231 | + [fooSymbol]); | 227 | 232 | } | 228 | 233 |
| 229 | 234 | // Verify that passing NULL to napi_set_property() results in the correct | |
Collapse file Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test_object.c +30Lines changed: 30 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +#define NAPI_EXPERIMENTAL | | 2 | + | 1 | 3 | #include <js_native_api.h> | 2 | 4 | #include "../common.h" | 3 | 5 | #include <string.h> | @@ -82,6 +84,33 @@ static napi_value GetPropertyNames(napi_env env, napi_callback_info info) { | 82 | 84 | return output; | 83 | 85 | } | 84 | 86 |
| | 87 | +static napi_value GetSymbolNames(napi_env env, napi_callback_info info) { | | 88 | + size_t argc = 1; | | 89 | + napi_value args[1]; | | 90 | + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); | | 91 | + | | 92 | + NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments"); | | 93 | + | | 94 | + napi_valuetype value_type0; | | 95 | + NAPI_CALL(env, napi_typeof(env, args[0], &value_type0)); | | 96 | + | | 97 | + NAPI_ASSERT(env, | | 98 | + value_type0 == napi_object, | | 99 | + "Wrong type of arguments. Expects an object as first argument."); | | 100 | + | | 101 | + napi_value output; | | 102 | + NAPI_CALL(env, | | 103 | + napi_get_all_property_names( | | 104 | + env, | | 105 | + args[0], | | 106 | + napi_key_include_prototypes, | | 107 | + napi_key_skip_strings, | | 108 | + napi_key_numbers_to_strings, | | 109 | + &output)); | | 110 | + | | 111 | + return output; | | 112 | +} | | 113 | + | 85 | 114 | static napi_value Set(napi_env env, napi_callback_info info) { | 86 | 115 | size_t argc = 3; | 87 | 116 | napi_value args[3]; | @@ -449,6 +478,7 @@ napi_value Init(napi_env env, napi_value exports) { | 449 | 478 | DECLARE_NAPI_PROPERTY("Get", Get), | 450 | 479 | DECLARE_NAPI_PROPERTY("GetNamed", GetNamed), | 451 | 480 | DECLARE_NAPI_PROPERTY("GetPropertyNames", GetPropertyNames), | | 481 | + DECLARE_NAPI_PROPERTY("GetSymbolNames", GetSymbolNames), | 452 | 482 | DECLARE_NAPI_PROPERTY("Set", Set), | 453 | 483 | DECLARE_NAPI_PROPERTY("SetNamed", SetNamed), | 454 | 484 | DECLARE_NAPI_PROPERTY("Has", Has), | |
|