|
264 | 264 | size_t argc = 2; |
265 | 265 | napi_value args[2]; |
266 | 266 | napi_value thisArg; |
267 | | - |
| 267 | + |
268 | 268 | napi_get_cb_info(env, info, &argc, args, &thisArg, nullptr); |
269 | | - |
| 269 | + |
270 | 270 | if (argc < 1) { |
271 | | - napi_throw_error(env, nullptr, "extend() requires at least one parameter with method definitions"); |
| 271 | + napi_throw_error(env, nullptr, |
| 272 | + "extend() requires at least one parameter with method definitions"); |
272 | 273 | return nullptr; |
273 | 274 | } |
274 | | - |
| 275 | + |
275 | 276 | // Validate that the first argument is an object |
276 | 277 | napi_valuetype argType; |
277 | 278 | napi_typeof(env, args[0], &argType); |
278 | 279 | if (argType != napi_object) { |
279 | 280 | napi_throw_error(env, nullptr, "extend() first parameter must be an object"); |
280 | 281 | return nullptr; |
281 | 282 | } |
282 | | - |
| 283 | + |
283 | 284 | // Get the native class from 'this' (the constructor function) |
284 | 285 | Class baseNativeClass = nullptr; |
285 | 286 | napi_unwrap(env, thisArg, (void**)&baseNativeClass); |
286 | | - |
| 287 | + |
287 | 288 | if (baseNativeClass == nullptr) { |
288 | 289 | napi_throw_error(env, nullptr, "extend() can only be called on native class constructors"); |
289 | 290 | return nullptr; |
290 | 291 | } |
291 | | - |
| 292 | + |
292 | 293 | // Create a unique class name |
293 | 294 | napi_value baseClassName; |
294 | 295 | napi_get_named_property(env, thisArg, "name", &baseClassName); |
295 | 296 | static char baseClassNameBuf[512]; |
296 | 297 | napi_get_value_string_utf8(env, baseClassName, baseClassNameBuf, 512, nullptr); |
297 | | - |
| 298 | + |
298 | 299 | std::string newClassName = baseClassNameBuf; |
299 | 300 | newClassName += "_Extended_"; |
300 | 301 | newClassName += std::to_string(rand()); |
301 | | - |
| 302 | + |
302 | 303 | // Create the new constructor function that extends the base |
303 | 304 | napi_value newConstructor; |
304 | | - napi_define_class(env, newClassName.c_str(), newClassName.length(), |
305 | | - [](napi_env env, napi_callback_info info) -> napi_value { |
306 | | - // Constructor implementation - delegate to base class |
307 | | - napi_value thisArg; |
308 | | - napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr); |
309 | | - return thisArg; |
310 | | - }, nullptr, 0, nullptr, &newConstructor); |
311 | | - |
| 305 | + napi_define_class(env, newClassName.c_str(), newClassName.length(), JS_BridgedConstructor, |
| 306 | + nullptr, 0, nullptr, &newConstructor); |
| 307 | + |
312 | 308 | // Set up JavaScript inheritance from the base class |
313 | 309 | napi_inherits(env, newConstructor, thisArg); |
314 | | - |
| 310 | + |
315 | 311 | // Get prototype for adding methods |
316 | 312 | napi_value newPrototype; |
317 | 313 | napi_get_named_property(env, newConstructor, "prototype", &newPrototype); |
318 | | - |
| 314 | + |
319 | 315 | // Add methods from the first parameter to the prototype |
320 | 316 | napi_value methodNames; |
321 | 317 | napi_get_all_property_names(env, args[0], napi_key_own_only, napi_key_skip_symbols, |
322 | 318 | napi_key_numbers_to_strings, &methodNames); |
323 | | - |
| 319 | + |
324 | 320 | uint32_t methodCount = 0; |
325 | 321 | napi_get_array_length(env, methodNames, &methodCount); |
326 | | - |
| 322 | + |
327 | 323 | for (uint32_t i = 0; i < methodCount; i++) { |
328 | 324 | napi_value methodName, methodFunc; |
329 | 325 | napi_get_element(env, methodNames, i, &methodName); |
330 | | - |
| 326 | + |
331 | 327 | static char methodNameBuf[512]; |
332 | 328 | napi_get_value_string_utf8(env, methodName, methodNameBuf, 512, nullptr); |
333 | 329 | std::string name = methodNameBuf; |
334 | | - |
| 330 | + |
335 | 331 | napi_get_named_property(env, args[0], name.c_str(), &methodFunc); |
336 | | - |
| 332 | + |
337 | 333 | // Add the method to the prototype |
338 | 334 | napi_set_named_property(env, newPrototype, name.c_str(), methodFunc); |
339 | 335 | } |
340 | | - |
| 336 | + |
341 | 337 | // Handle optional second parameter for protocols |
342 | 338 | if (argc >= 2) { |
343 | 339 | napi_valuetype secondArgType; |
|
346 | 342 | napi_value protocols; |
347 | 343 | bool hasProtocols = false; |
348 | 344 | napi_has_named_property(env, args[1], "protocols", &hasProtocols); |
349 | | - |
| 345 | + |
350 | 346 | if (hasProtocols) { |
351 | 347 | napi_get_named_property(env, args[1], "protocols", &protocols); |
352 | 348 | napi_set_named_property(env, newConstructor, "ObjCProtocols", protocols); |
353 | 349 | } |
354 | 350 | } |
355 | 351 | } |
356 | | - |
| 352 | + |
357 | 353 | // Use ClassBuilder to create the native class and bridge the methods |
358 | 354 | ClassBuilder* builder = new ClassBuilder(env, newConstructor); |
359 | 355 | builder->build(); |
360 | | - |
| 356 | + |
361 | 357 | // Register the builder in the bridge state |
362 | 358 | auto bridgeState = ObjCBridgeState::InstanceData(env); |
363 | 359 | bridgeState->classesByPointer[builder->nativeClass] = builder; |
364 | | - |
| 360 | + |
365 | 361 | return newConstructor; |
366 | 362 | } |
367 | 363 |
|
|
0 commit comments