@@ -15,35 +15,69 @@ pub unsafe extern "C" fn new(out: &mut Local, env: Env) {
1515/// Mutates the `out` argument to refer to a `napi_value` containing the own property names of the
1616/// `object` as a JavaScript Array.
1717pub unsafe extern "C" fn get_own_property_names ( out : & mut Local , env : Env , object : Local ) -> bool {
18- let status = napi:: napi_get_property_names ( env, object, out as * mut _ ) ;
19-
20- if status != napi:: napi_status:: napi_ok {
18+ // Node.js 13+ have `napi_get_all_property_names`, which does the conversion right and allows
19+ // us to ask for only own properties or prototype properties or anything we like.
20+ // Unfortunately, earlier versions do not support that method, so we have to implement it
21+ // manually.
22+ //
23+ // So we use a temporary array for the raw names:
24+ let mut raw_names = MaybeUninit :: uninit ( ) ;
25+ if napi:: napi_get_property_names ( env, object, raw_names. as_mut_ptr ( ) ) != napi:: napi_status:: napi_ok {
26+ return false ;
27+ }
28+ // And a "fixed" array for the actual return value:
29+ let mut fixed_names = MaybeUninit :: uninit ( ) ;
30+ if napi:: napi_create_array ( env, fixed_names. as_mut_ptr ( ) ) != napi:: napi_status:: napi_ok {
2131 return false ;
2232 }
2333
24- // Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
25- // numbers for numeric indices instead of strings.
26- let len = array:: len ( env, * out) ;
27- for index in 0 ..len {
28- let mut element: Local = std:: mem:: zeroed ( ) ;
34+ let raw_names = raw_names. assume_init ( ) ;
35+ let mut fixed_names = fixed_names. assume_init ( ) ;
36+
37+ * out = fixed_names;
38+
39+ let raw_len = array:: len ( env, raw_names) ;
40+ let mut fixed_len = 0 ;
41+ for index in 0 ..raw_len {
42+ let mut property_name: Local = std:: mem:: zeroed ( ) ;
43+
2944 // In general, getters may cause arbitrary JS code to be run, but this is a newly created
3045 // Array from an official internal API so it doesn't do anything strange.
31- if !get_index ( & mut element, env, * out, index) {
32- continue ;
33- }
34- if tag:: is_string ( env, element) {
46+ if !get_index ( & mut property_name, env, raw_names, index) {
3547 continue ;
3648 }
37- let mut stringified: Local = std:: mem:: zeroed ( ) ;
38- // If we can't convert to a string, something went wrong.
39- if !convert:: to_string ( & mut stringified, env, element) {
49+
50+ let mut is_own_property = false ;
51+ // May return a non-OK status if `key` is not a string or a Symbol, but here it is always
52+ // a string.
53+ if napi:: napi_has_own_property ( env, object, property_name, & mut is_own_property as * mut _ ) != napi:: napi_status:: napi_ok {
4054 return false ;
4155 }
56+
57+ if !is_own_property {
58+ continue ;
59+ }
60+
61+ // Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
62+ // numbers for numeric indices instead of strings.
63+ // Make sure we always return strings.
64+ let property_name = if !tag:: is_string ( env, property_name) {
65+ let mut stringified: Local = std:: mem:: zeroed ( ) ;
66+ // If we can't convert to a string, something went wrong.
67+ if !convert:: to_string ( & mut stringified, env, property_name) {
68+ return false ;
69+ }
70+ stringified
71+ } else {
72+ property_name
73+ } ;
74+
4275 let mut dummy = false ;
4376 // If we can't convert assign to this array, something went wrong.
44- if !set_index ( & mut dummy, env, * out , index , stringified ) {
77+ if !set_index ( & mut dummy, env, fixed_names , fixed_len , property_name ) {
4578 return false ;
4679 }
80+ fixed_len += 1 ;
4781 }
4882
4983 true
0 commit comments