1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "object.h"
17
18 #include <base/containers/string.h>
19
20 #include "TrueRootObject.h"
21 #include "function.h"
22 #include "utils.h"
23
24 namespace NapiApi {
25
Object(napi_env env)26 Object::Object(napi_env env) : env_(env)
27 {
28 if (!env_) {
29 return;
30 }
31 napi_create_object(env, &object_);
32 if (object_) {
33 napi_typeof(env, object_, &jstype);
34 }
35 if (jstype != napi_object) {
36 // value was not an object!
37 env_ = {};
38 object_ = nullptr;
39 jstype = napi_undefined;
40 }
41 }
42
Object(napi_env env,napi_value v)43 Object::Object(napi_env env, napi_value v) : env_(env), object_(v)
44 {
45 if (!env_) {
46 return;
47 }
48 if (v) {
49 napi_typeof(env_, v, &jstype);
50 }
51 if (jstype != napi_object) {
52 // value was not an object!
53 env_ = {};
54 object_ = nullptr;
55 jstype = napi_undefined;
56 }
57 }
58
Object(napi_env env,BASE_NS::string_view className,const JsFuncArgs & args)59 Object::Object(napi_env env, BASE_NS::string_view className, const JsFuncArgs& args) : env_(env)
60 {
61 NapiApi::MyInstanceState* mis {};
62 NapiApi::MyInstanceState::GetInstance(env, (void**)&mis);
63 if (mis) {
64 const auto ctor = NapiApi::Function(env, mis->FetchCtor(className));
65
66 napi_new_instance(env_, ctor, args.argc, args.argv, &object_);
67 if (object_) {
68 napi_typeof(env_, object_, &jstype);
69 }
70 if (jstype != napi_object) {
71 // value was not an object!
72 env_ = {};
73 object_ = nullptr;
74 jstype = napi_undefined;
75 }
76 }
77 }
78
ToNapiValue() const79 napi_value Object::ToNapiValue() const
80 {
81 return object_;
82 }
83
GetEnv() const84 napi_env Object::GetEnv() const
85 {
86 return env_;
87 }
88
GetRoot() const89 TrueRootObject* Object::GetRoot() const
90 {
91 return GetInterface<TrueRootObject>();
92 }
93
GetNative() const94 META_NS::IObject::Ptr Object::GetNative() const
95 {
96 if (auto tro = GetRoot()) {
97 return tro->GetNativeObject();
98 }
99 return {};
100 }
101
Get(const BASE_NS::string_view name)102 napi_value Object::Get(const BASE_NS::string_view name)
103 {
104 auto tmp = GetNamedPropertyAndType(name);
105 if (tmp.jstype == napi_null) {
106 return nullptr;
107 }
108 if (tmp.jstype == napi_undefined) {
109 return nullptr;
110 }
111 return tmp.res;
112 }
113
Set(const BASE_NS::string_view name,napi_value value)114 void Object::Set(const BASE_NS::string_view name, napi_value value)
115 {
116 if (!env_ || !object_) {
117 return;
118 }
119 // could check if it is declared. and optionally add it. (now it just adds it if not declared)
120 napi_set_named_property(env_, object_, BASE_NS::string(name).c_str(), value);
121 }
122
Set(const BASE_NS::string_view name,const Object & value)123 void Object::Set(const BASE_NS::string_view name, const Object& value)
124 {
125 Set(name, value.ToNapiValue());
126 }
127
Set(const BASE_NS::string_view name,const BASE_NS::string_view v)128 void Object::Set(const BASE_NS::string_view name, const BASE_NS::string_view v)
129 {
130 if (!env_ || !object_) {
131 return;
132 }
133 napi_status status;
134 napi_value value = MakeTempString(v);
135 status = napi_set_named_property(env_, object_, BASE_NS::string(name).c_str(), value);
136 }
137
operator bool() const138 Object::operator bool() const
139 {
140 if (!env_ || !object_) {
141 return false;
142 }
143 return (napi_object == jstype);
144 }
145
Has(const BASE_NS::string_view name)146 bool Object::Has(const BASE_NS::string_view name)
147 {
148 if (!env_ || !object_) {
149 return false;
150 }
151 bool res;
152 napi_value key = MakeTempString(name);
153 napi_status status = napi_has_property(env_, object_, key, &res);
154 if (napi_ok != status) {
155 return false;
156 }
157 return res;
158 }
159
IsNull() const160 bool Object::IsNull() const
161 {
162 return (napi_null == jstype);
163 }
164
IsNull(const BASE_NS::string_view name)165 bool Object::IsNull(const BASE_NS::string_view name)
166 {
167 auto tmp = GetNamedPropertyAndType(name);
168 if (!tmp.success) {
169 return true;
170 }
171 return (tmp.jstype == napi_null);
172 }
173
IsDefined() const174 bool Object::IsDefined() const
175 {
176 return (napi_undefined != jstype);
177 }
178
IsUndefined(const BASE_NS::string_view name)179 bool Object::IsUndefined(const BASE_NS::string_view name)
180 {
181 auto tmp = GetNamedPropertyAndType(name);
182 if (!tmp.success) {
183 return true;
184 }
185 return (tmp.jstype == napi_undefined);
186 }
187
IsUndefinedOrNull(const BASE_NS::string_view name)188 bool Object::IsUndefinedOrNull(const BASE_NS::string_view name)
189 {
190 auto tmp = GetNamedPropertyAndType(name);
191 if (!tmp.success) {
192 return true;
193 }
194 return ((tmp.jstype == napi_null) || (tmp.jstype == napi_undefined));
195 }
196
IsSame(const Object & other) const197 bool Object::IsSame(const Object& other) const
198 {
199 return object_ == other.object_;
200 }
201
StrictEqual(const Object & other) const202 bool Object::StrictEqual(const Object& other) const
203 {
204 if (!env_) {
205 CORE_LOG_F("Unitialized object, can't compare strict equality");
206 assert(false);
207 return false;
208 }
209
210 bool equal = false;
211 napi_strict_equals(env_, object_, other.object_, &equal);
212 return equal;
213 }
214
AddProperty(const napi_property_descriptor desc)215 void Object::AddProperty(const napi_property_descriptor desc)
216 {
217 if (!env_ || !object_) {
218 return;
219 }
220 napi_status status = napi_define_properties(env_, object_, 1, &desc);
221 }
222
DeleteProperty(const BASE_NS::string_view name)223 bool Object::DeleteProperty(const BASE_NS::string_view name)
224 {
225 if (!env_ || !object_) {
226 return false;
227 }
228 // remove property from object.
229 napi_status status;
230 bool result { false };
231 napi_value key = MakeTempString(name);
232 status = napi_delete_property(env_, object_, key, &result);
233 return result;
234 }
235
GetNamedPropertyAndType(const BASE_NS::string_view name)236 Object::NameAndType Object::GetNamedPropertyAndType(const BASE_NS::string_view name)
237 {
238 napi_value res;
239 napi_status status;
240 napi_valuetype jstype;
241 if (!env_ || !object_) {
242 return { false, nullptr, napi_undefined };
243 }
244 status = napi_get_named_property(env_, object_, BASE_NS::string(name).c_str(), &res);
245 if ((!res) || (napi_ok != status)) {
246 return { false, nullptr, napi_undefined };
247 }
248 napi_typeof(env_, res, &jstype);
249 return { true, res, jstype };
250 }
251
MakeTempString(const BASE_NS::string_view v)252 napi_value Object::MakeTempString(const BASE_NS::string_view v)
253 {
254 return env_.GetString(v);
255 }
256
257 } // namespace NapiApi
258