nodenetcdf 4.9.31 → 4.9.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/Attribute.cpp +15 -0
- package/src/File.cpp +18 -2
- package/src/Group.cpp +108 -14
- package/src/Variable.cpp +50 -6
- package/test/json.js +41 -3
package/package.json
CHANGED
package/src/Attribute.cpp
CHANGED
|
@@ -365,6 +365,21 @@ void Attribute::ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
|
365
365
|
}
|
|
366
366
|
value = v8::Null(isolate);
|
|
367
367
|
}
|
|
368
|
+
else if (value->IsTypedArray())
|
|
369
|
+
{
|
|
370
|
+
// Convert TypedArray to regular array for JSON serialization
|
|
371
|
+
v8::Local<v8::TypedArray> typedArray = v8::Local<v8::TypedArray>::Cast(value);
|
|
372
|
+
uint32_t length = typedArray->Length();
|
|
373
|
+
v8::Local<v8::Array> array = v8::Array::New(isolate, length);
|
|
374
|
+
|
|
375
|
+
for (uint32_t i = 0; i < length; i++)
|
|
376
|
+
{
|
|
377
|
+
v8::Local<v8::Value> element = typedArray->Get(context, i).ToLocalChecked();
|
|
378
|
+
(void)array->Set(context, i, element);
|
|
379
|
+
}
|
|
380
|
+
value = array;
|
|
381
|
+
}
|
|
382
|
+
// Don't wrap primitives - only convert TypedArrays to arrays
|
|
368
383
|
|
|
369
384
|
(void)json->CreateDataProperty(context, value_str, value);
|
|
370
385
|
|
package/src/File.cpp
CHANGED
|
@@ -174,11 +174,27 @@ void File::ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
|
174
174
|
v8::Isolate *isolate = args.GetIsolate();
|
|
175
175
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
|
176
176
|
|
|
177
|
-
// Get the root group
|
|
177
|
+
// Get the root group
|
|
178
178
|
v8::Local<v8::String> rootProp = v8::String::NewFromUtf8(isolate, "root", v8::NewStringType::kNormal).ToLocalChecked();
|
|
179
179
|
v8::Local<v8::Value> root = args.Holder()->Get(context, rootProp).ToLocalChecked();
|
|
180
180
|
|
|
181
|
-
//
|
|
181
|
+
// Call toJSON on the root group to get proper array conversion
|
|
182
|
+
if (root->IsObject())
|
|
183
|
+
{
|
|
184
|
+
v8::Local<v8::Object> rootObj = root->ToObject(context).ToLocalChecked();
|
|
185
|
+
v8::Local<v8::String> toJSONProp = v8::String::NewFromUtf8(isolate, "toJSON", v8::NewStringType::kNormal).ToLocalChecked();
|
|
186
|
+
v8::Local<v8::Value> toJSONMethod = rootObj->Get(context, toJSONProp).ToLocalChecked();
|
|
187
|
+
|
|
188
|
+
if (toJSONMethod->IsFunction())
|
|
189
|
+
{
|
|
190
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSONMethod);
|
|
191
|
+
v8::Local<v8::Value> result = toJSONFunc->Call(context, rootObj, 0, nullptr).ToLocalChecked();
|
|
192
|
+
args.GetReturnValue().Set(result);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Fallback: return root as-is
|
|
182
198
|
args.GetReturnValue().Set(root);
|
|
183
199
|
}
|
|
184
200
|
} // namespace nodenetcdfjs
|
package/src/Group.cpp
CHANGED
|
@@ -525,30 +525,124 @@ void Group::ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
|
525
525
|
}
|
|
526
526
|
}
|
|
527
527
|
|
|
528
|
-
//
|
|
529
|
-
// These will be accessed through property getters which trigger the respective Get* methods
|
|
528
|
+
// Convert dimensions object to array, calling toJSON on each item
|
|
530
529
|
v8::Local<v8::Value> dimensions = args.Holder()->Get(context, dimensions_str).ToLocalChecked();
|
|
531
|
-
if (dimensions->IsObject())
|
|
532
|
-
{
|
|
533
|
-
|
|
530
|
+
if (dimensions->IsObject() && !dimensions->IsNull())
|
|
531
|
+
{
|
|
532
|
+
v8::Local<v8::Object> dimsObj = dimensions->ToObject(context).ToLocalChecked();
|
|
533
|
+
v8::Local<v8::Array> propNames = dimsObj->GetOwnPropertyNames(context).ToLocalChecked();
|
|
534
|
+
v8::Local<v8::Array> dimsArray = v8::Array::New(isolate, propNames->Length());
|
|
535
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
536
|
+
|
|
537
|
+
for (uint32_t i = 0; i < propNames->Length(); i++)
|
|
538
|
+
{
|
|
539
|
+
v8::Local<v8::Value> key = propNames->Get(context, i).ToLocalChecked();
|
|
540
|
+
v8::Local<v8::Value> value = dimsObj->Get(context, key).ToLocalChecked();
|
|
541
|
+
|
|
542
|
+
// Call toJSON if available to ensure proper serialization
|
|
543
|
+
if (value->IsObject())
|
|
544
|
+
{
|
|
545
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
546
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
547
|
+
if (toJSON->IsFunction())
|
|
548
|
+
{
|
|
549
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
550
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
(void)dimsArray->Set(context, i, value);
|
|
554
|
+
}
|
|
555
|
+
(void)json->CreateDataProperty(context, dimensions_str, dimsArray);
|
|
534
556
|
}
|
|
535
557
|
|
|
558
|
+
// Convert variables object to array, calling toJSON on each item
|
|
536
559
|
v8::Local<v8::Value> variables = args.Holder()->Get(context, variables_str).ToLocalChecked();
|
|
537
|
-
if (variables->IsObject())
|
|
538
|
-
{
|
|
539
|
-
|
|
560
|
+
if (variables->IsObject() && !variables->IsNull())
|
|
561
|
+
{
|
|
562
|
+
v8::Local<v8::Object> varsObj = variables->ToObject(context).ToLocalChecked();
|
|
563
|
+
v8::Local<v8::Array> propNames = varsObj->GetOwnPropertyNames(context).ToLocalChecked();
|
|
564
|
+
v8::Local<v8::Array> varsArray = v8::Array::New(isolate, propNames->Length());
|
|
565
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
566
|
+
|
|
567
|
+
for (uint32_t i = 0; i < propNames->Length(); i++)
|
|
568
|
+
{
|
|
569
|
+
v8::Local<v8::Value> key = propNames->Get(context, i).ToLocalChecked();
|
|
570
|
+
v8::Local<v8::Value> value = varsObj->Get(context, key).ToLocalChecked();
|
|
571
|
+
|
|
572
|
+
// Call toJSON if available to ensure proper serialization
|
|
573
|
+
if (value->IsObject())
|
|
574
|
+
{
|
|
575
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
576
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
577
|
+
if (toJSON->IsFunction())
|
|
578
|
+
{
|
|
579
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
580
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
(void)varsArray->Set(context, i, value);
|
|
584
|
+
}
|
|
585
|
+
(void)json->CreateDataProperty(context, variables_str, varsArray);
|
|
540
586
|
}
|
|
541
587
|
|
|
588
|
+
// Convert attributes object to array, calling toJSON on each item
|
|
542
589
|
v8::Local<v8::Value> attributes = args.Holder()->Get(context, attributes_str).ToLocalChecked();
|
|
543
|
-
if (attributes->IsObject())
|
|
544
|
-
{
|
|
545
|
-
|
|
590
|
+
if (attributes->IsObject() && !attributes->IsNull())
|
|
591
|
+
{
|
|
592
|
+
v8::Local<v8::Object> attrsObj = attributes->ToObject(context).ToLocalChecked();
|
|
593
|
+
v8::Local<v8::Array> propNames = attrsObj->GetOwnPropertyNames(context).ToLocalChecked();
|
|
594
|
+
v8::Local<v8::Array> attrsArray = v8::Array::New(isolate, propNames->Length());
|
|
595
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
596
|
+
|
|
597
|
+
for (uint32_t i = 0; i < propNames->Length(); i++)
|
|
598
|
+
{
|
|
599
|
+
v8::Local<v8::Value> key = propNames->Get(context, i).ToLocalChecked();
|
|
600
|
+
v8::Local<v8::Value> value = attrsObj->Get(context, key).ToLocalChecked();
|
|
601
|
+
|
|
602
|
+
// Call toJSON if available to ensure proper serialization
|
|
603
|
+
if (value->IsObject())
|
|
604
|
+
{
|
|
605
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
606
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
607
|
+
if (toJSON->IsFunction())
|
|
608
|
+
{
|
|
609
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
610
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
(void)attrsArray->Set(context, i, value);
|
|
614
|
+
}
|
|
615
|
+
(void)json->CreateDataProperty(context, attributes_str, attrsArray);
|
|
546
616
|
}
|
|
547
617
|
|
|
618
|
+
// Convert subgroups object to array, calling toJSON on each item
|
|
548
619
|
v8::Local<v8::Value> subgroups = args.Holder()->Get(context, subgroups_str).ToLocalChecked();
|
|
549
|
-
if (subgroups->IsObject())
|
|
550
|
-
{
|
|
551
|
-
|
|
620
|
+
if (subgroups->IsObject() && !subgroups->IsNull())
|
|
621
|
+
{
|
|
622
|
+
v8::Local<v8::Object> subgrpsObj = subgroups->ToObject(context).ToLocalChecked();
|
|
623
|
+
v8::Local<v8::Array> propNames = subgrpsObj->GetOwnPropertyNames(context).ToLocalChecked();
|
|
624
|
+
v8::Local<v8::Array> subgrpsArray = v8::Array::New(isolate, propNames->Length());
|
|
625
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
626
|
+
|
|
627
|
+
for (uint32_t i = 0; i < propNames->Length(); i++)
|
|
628
|
+
{
|
|
629
|
+
v8::Local<v8::Value> key = propNames->Get(context, i).ToLocalChecked();
|
|
630
|
+
v8::Local<v8::Value> value = subgrpsObj->Get(context, key).ToLocalChecked();
|
|
631
|
+
|
|
632
|
+
// Call toJSON if available to ensure proper serialization
|
|
633
|
+
if (value->IsObject())
|
|
634
|
+
{
|
|
635
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
636
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
637
|
+
if (toJSON->IsFunction())
|
|
638
|
+
{
|
|
639
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
640
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
(void)subgrpsArray->Set(context, i, value);
|
|
644
|
+
}
|
|
645
|
+
(void)json->CreateDataProperty(context, subgroups_str, subgrpsArray);
|
|
552
646
|
}
|
|
553
647
|
|
|
554
648
|
args.GetReturnValue().Set(json);
|
package/src/Variable.cpp
CHANGED
|
@@ -1383,18 +1383,62 @@ void Variable::ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args)
|
|
|
1383
1383
|
(void)json->CreateDataProperty(context, type_str,
|
|
1384
1384
|
v8::String::NewFromUtf8(isolate, type_name, v8::NewStringType::kInternalized).ToLocalChecked());
|
|
1385
1385
|
|
|
1386
|
-
//
|
|
1386
|
+
// Dimensions are already an array, but call toJSON on each item
|
|
1387
1387
|
v8::Local<v8::Value> dimensions = args.Holder()->Get(context, dimensions_str).ToLocalChecked();
|
|
1388
1388
|
if (dimensions->IsArray())
|
|
1389
1389
|
{
|
|
1390
|
-
|
|
1390
|
+
v8::Local<v8::Array> dimsArray = v8::Local<v8::Array>::Cast(dimensions);
|
|
1391
|
+
v8::Local<v8::Array> newDimsArray = v8::Array::New(isolate, dimsArray->Length());
|
|
1392
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
1393
|
+
|
|
1394
|
+
for (uint32_t i = 0; i < dimsArray->Length(); i++)
|
|
1395
|
+
{
|
|
1396
|
+
v8::Local<v8::Value> value = dimsArray->Get(context, i).ToLocalChecked();
|
|
1397
|
+
|
|
1398
|
+
// Call toJSON if available to ensure proper serialization
|
|
1399
|
+
if (value->IsObject())
|
|
1400
|
+
{
|
|
1401
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
1402
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
1403
|
+
if (toJSON->IsFunction())
|
|
1404
|
+
{
|
|
1405
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
1406
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
(void)newDimsArray->Set(context, i, value);
|
|
1410
|
+
}
|
|
1411
|
+
(void)json->CreateDataProperty(context, dimensions_str, newDimsArray);
|
|
1391
1412
|
}
|
|
1392
1413
|
|
|
1393
|
-
//
|
|
1414
|
+
// Convert attributes object to array, calling toJSON on each item
|
|
1394
1415
|
v8::Local<v8::Value> attributes = args.Holder()->Get(context, attributes_str).ToLocalChecked();
|
|
1395
|
-
if (attributes->IsObject())
|
|
1396
|
-
{
|
|
1397
|
-
|
|
1416
|
+
if (attributes->IsObject() && !attributes->IsNull())
|
|
1417
|
+
{
|
|
1418
|
+
v8::Local<v8::Object> attrsObj = attributes->ToObject(context).ToLocalChecked();
|
|
1419
|
+
v8::Local<v8::Array> propNames = attrsObj->GetOwnPropertyNames(context).ToLocalChecked();
|
|
1420
|
+
v8::Local<v8::Array> attrsArray = v8::Array::New(isolate, propNames->Length());
|
|
1421
|
+
v8::Local<v8::String> toJSONStr = v8::String::NewFromUtf8Literal(isolate, "toJSON");
|
|
1422
|
+
|
|
1423
|
+
for (uint32_t i = 0; i < propNames->Length(); i++)
|
|
1424
|
+
{
|
|
1425
|
+
v8::Local<v8::Value> key = propNames->Get(context, i).ToLocalChecked();
|
|
1426
|
+
v8::Local<v8::Value> value = attrsObj->Get(context, key).ToLocalChecked();
|
|
1427
|
+
|
|
1428
|
+
// Call toJSON if available to ensure proper serialization
|
|
1429
|
+
if (value->IsObject())
|
|
1430
|
+
{
|
|
1431
|
+
v8::Local<v8::Object> valueObj = value->ToObject(context).ToLocalChecked();
|
|
1432
|
+
v8::Local<v8::Value> toJSON = valueObj->Get(context, toJSONStr).ToLocalChecked();
|
|
1433
|
+
if (toJSON->IsFunction())
|
|
1434
|
+
{
|
|
1435
|
+
v8::Local<v8::Function> toJSONFunc = v8::Local<v8::Function>::Cast(toJSON);
|
|
1436
|
+
value = toJSONFunc->Call(context, valueObj, 0, nullptr).ToLocalChecked();
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
(void)attrsArray->Set(context, i, value);
|
|
1440
|
+
}
|
|
1441
|
+
(void)json->CreateDataProperty(context, attributes_str, attrsArray);
|
|
1398
1442
|
}
|
|
1399
1443
|
|
|
1400
1444
|
args.GetReturnValue().Set(json);
|
package/test/json.js
CHANGED
|
@@ -63,6 +63,40 @@ describe('JSON Serialization', function() {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
|
+
|
|
67
|
+
it('should not serialize attribute values as null', function() {
|
|
68
|
+
// Check all attributes in file don't have null values when serialized
|
|
69
|
+
var jsonStr = JSON.stringify(file);
|
|
70
|
+
var nullMatches = jsonStr.match(/"value":\s*null/g);
|
|
71
|
+
var nullCount = nullMatches ? nullMatches.length : 0;
|
|
72
|
+
|
|
73
|
+
expect(nullCount).to.equal(0, 'Found ' + nullCount + ' null attribute values in JSON');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should convert TypedArray values to regular arrays in JSON', function() {
|
|
77
|
+
// Find an attribute with a TypedArray value
|
|
78
|
+
var variables = file.root.variables;
|
|
79
|
+
for (var varName in variables) {
|
|
80
|
+
var variable = variables[varName];
|
|
81
|
+
var varAttrs = variable.attributes;
|
|
82
|
+
for (var attrName in varAttrs) {
|
|
83
|
+
var attr = varAttrs[attrName];
|
|
84
|
+
|
|
85
|
+
// Check if value is a TypedArray
|
|
86
|
+
if (attr.value && typeof attr.value === 'object' &&
|
|
87
|
+
attr.value.constructor && attr.value.constructor.name.includes('Array') &&
|
|
88
|
+
!Array.isArray(attr.value)) {
|
|
89
|
+
|
|
90
|
+
// It's a TypedArray, test it converts to regular array
|
|
91
|
+
var json = JSON.parse(JSON.stringify(attr));
|
|
92
|
+
|
|
93
|
+
// In JSON, it should be a regular array
|
|
94
|
+
expect(Array.isArray(json.value)).to.be.true;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
66
100
|
});
|
|
67
101
|
|
|
68
102
|
describe('Variable', function() {
|
|
@@ -130,11 +164,15 @@ describe('JSON Serialization', function() {
|
|
|
130
164
|
it('should recursively serialize entire file structure', function() {
|
|
131
165
|
var json = JSON.parse(JSON.stringify(file));
|
|
132
166
|
|
|
133
|
-
// File should serialize as root group with all children
|
|
167
|
+
// File should serialize as root group with all children as arrays
|
|
134
168
|
expect(json).to.have.property('dimensions');
|
|
135
169
|
expect(json).to.have.property('variables');
|
|
136
|
-
expect(json
|
|
137
|
-
expect(json
|
|
170
|
+
expect(json).to.have.property('attributes');
|
|
171
|
+
expect(json).to.have.property('subgroups');
|
|
172
|
+
expect(json.variables).to.be.an('array');
|
|
173
|
+
expect(json.dimensions).to.be.an('array');
|
|
174
|
+
expect(json.attributes).to.be.an('array');
|
|
175
|
+
expect(json.subgroups).to.be.an('array');
|
|
138
176
|
});
|
|
139
177
|
});
|
|
140
178
|
});
|