nodenetcdf 4.9.3 → 4.9.32

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/TYPESCRIPT.md ADDED
@@ -0,0 +1,211 @@
1
+ # TypeScript Support
2
+
3
+ This package includes TypeScript type definitions for full IntelliSense and type safety when using the NetCDF4 library in TypeScript projects.
4
+
5
+ ## Installation
6
+
7
+ The type definitions are automatically included when you install the package:
8
+
9
+ ```bash
10
+ npm install nodenetcdf
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Importing
16
+
17
+ ```typescript
18
+ import { File, Group, Variable, Dimension, Attribute } from 'nodenetcdf';
19
+ ```
20
+
21
+ ### Type Definitions
22
+
23
+ The package exports the following types:
24
+
25
+ - **Classes**: `File`, `Group`, `Variable`, `Dimension`, `Attribute`
26
+ - **Type Aliases**: `NetCDFDataType`, `FileMode`, `FileFormat`, `Endianness`, `ChecksumMode`, `ChunkMode`, `FillMode`
27
+
28
+ ### Example Usage
29
+
30
+ ```typescript
31
+ import { File, NetCDFDataType } from 'nodenetcdf';
32
+
33
+ // Create a new NetCDF file
34
+ const file = new File('output.nc', 'c!', 'nodenetcdf');
35
+
36
+ // Access the root group (fully typed)
37
+ const root = file.root;
38
+
39
+ // Add dimensions with type safety
40
+ const timeDim = root.addDimension('time', 0); // unlimited dimension
41
+ const latDim = root.addDimension('lat', 180);
42
+ const lonDim = root.addDimension('lon', 360);
43
+
44
+ // Add variables with proper typing
45
+ const tempVar = root.addVariable('temperature', 'float', [timeDim, latDim, lonDim]);
46
+
47
+ // Set variable properties with autocomplete support
48
+ tempVar.endianness = 'little';
49
+ tempVar.compressionLevel = 6;
50
+ tempVar.fillValue = -999.0;
51
+
52
+ // Add attributes (type-checked)
53
+ tempVar.addAttribute('units', 'string', 'degrees_C');
54
+ tempVar.addAttribute('long_name', 'string', 'Air Temperature');
55
+
56
+ // Write and read data with type safety
57
+ tempVar.write(data);
58
+ const retrievedData = tempVar.read();
59
+
60
+ // Sync and close
61
+ file.sync();
62
+ file.close();
63
+ ```
64
+
65
+ ## Available Types
66
+
67
+ ### NetCDFDataType
68
+
69
+ ```typescript
70
+ type NetCDFDataType =
71
+ | 'byte'
72
+ | 'char'
73
+ | 'short'
74
+ | 'int'
75
+ | 'float'
76
+ | 'double'
77
+ | 'ubyte'
78
+ | 'ushort'
79
+ | 'uint'
80
+ | 'int64'
81
+ | 'string';
82
+ ```
83
+
84
+ ### FileMode
85
+
86
+ ```typescript
87
+ type FileMode =
88
+ | 'r' // Read-only
89
+ | 'w' // Read-write
90
+ | 'c' // Create (no clobber)
91
+ | 'c!'; // Create (clobber/overwrite)
92
+ ```
93
+
94
+ ### FileFormat
95
+
96
+ ```typescript
97
+ type FileFormat =
98
+ | 'classic' // Classic NetCDF format
99
+ | 'classic64' // 64-bit offset format
100
+ | 'nodenetcdf' // NetCDF-4 format
101
+ | 'nodenetcdfclassic'; // NetCDF-4 classic model
102
+ ```
103
+
104
+ ## API Documentation
105
+
106
+ ### File Class
107
+
108
+ ```typescript
109
+ class File {
110
+ constructor(filename: string, mode: FileMode, format?: FileFormat);
111
+ readonly root: Group;
112
+ sync(): void;
113
+ close(): void;
114
+ inspect(): string;
115
+ }
116
+ ```
117
+
118
+ ### Group Class
119
+
120
+ ```typescript
121
+ class Group {
122
+ readonly id: number;
123
+ readonly variables: { [name: string]: Variable };
124
+ readonly dimensions: { [name: string]: Dimension };
125
+ readonly unlimited: Dimension | null;
126
+ readonly attributes: { [name: string]: Attribute };
127
+ readonly subgroups: { [name: string]: Group };
128
+ readonly name: string;
129
+ readonly fullname: string;
130
+
131
+ addAttribute(name: string, type: NetCDFDataType, value: any): Attribute;
132
+ addDimension(name: string, length: number): Dimension;
133
+ addSubgroup(name: string): Group;
134
+ addVariable(name: string, type: NetCDFDataType, dimensions: (string | Dimension)[]): Variable;
135
+ inspect(): string;
136
+ }
137
+ ```
138
+
139
+ ### Variable Class
140
+
141
+ ```typescript
142
+ class Variable {
143
+ readonly id: number;
144
+ readonly type: NetCDFDataType;
145
+ readonly dimensions: Dimension[];
146
+ readonly attributes: { [name: string]: Attribute };
147
+ name: string;
148
+ endianness: Endianness;
149
+ checksumMode: ChecksumMode;
150
+ chunkMode: ChunkMode;
151
+ chunkSizes: number[];
152
+ fillMode: FillMode;
153
+ fillValue: any;
154
+ compressionShuffle: boolean;
155
+ compressionDeflate: boolean;
156
+ compressionLevel: number;
157
+
158
+ read(): any;
159
+ readSlice(start: number[], count: number[]): any;
160
+ readStridedSlice(start: number[], count: number[], stride: number[]): any;
161
+ write(data: any): void;
162
+ writeSlice(start: number[], count: number[], data: any): void;
163
+ writeStridedSlice(start: number[], count: number[], stride: number[], data: any): void;
164
+ addAttribute(name: string, type: NetCDFDataType, value: any): Attribute;
165
+ inspect(): string;
166
+ }
167
+ ```
168
+
169
+ ### Dimension Class
170
+
171
+ ```typescript
172
+ class Dimension {
173
+ readonly id: number;
174
+ readonly length: number;
175
+ name: string;
176
+ inspect(): string;
177
+ }
178
+ ```
179
+
180
+ ### Attribute Class
181
+
182
+ ```typescript
183
+ class Attribute {
184
+ name: string;
185
+ value: any;
186
+ delete(): void;
187
+ inspect(): string;
188
+ }
189
+ ```
190
+
191
+ ## Benefits of TypeScript Support
192
+
193
+ 1. **IntelliSense**: Get autocomplete suggestions for all methods and properties
194
+ 2. **Type Safety**: Catch type errors at compile time instead of runtime
195
+ 3. **Documentation**: Inline documentation available in your IDE
196
+ 4. **Refactoring**: Safely rename and refactor code with confidence
197
+ 5. **Error Prevention**: Prevent common mistakes like invalid file modes or data types
198
+
199
+ ## Testing
200
+
201
+ The package includes a TypeScript test file to verify the type definitions:
202
+
203
+ ```bash
204
+ npx tsc test/typescript-test.ts --noEmit --skipLibCheck
205
+ ```
206
+
207
+ This ensures all type definitions are correct and complete.
208
+
209
+ ## Contributing
210
+
211
+ If you find any issues with the type definitions or have suggestions for improvements, please open an issue on the GitHub repository.
package/index.d.ts ADDED
@@ -0,0 +1,389 @@
1
+ // Type definitions for nodenetcdf
2
+ // Project: https://github.com/pheonixfirewingz/netcdf4
3
+ // Definitions by: Luke Shore <luke.a.shore@oliva.energy>
4
+
5
+ /**
6
+ * NetCDF data types
7
+ */
8
+ export type NetCDFDataType =
9
+ | 'byte'
10
+ | 'char'
11
+ | 'short'
12
+ | 'int'
13
+ | 'float'
14
+ | 'double'
15
+ | 'ubyte'
16
+ | 'ushort'
17
+ | 'uint'
18
+ | 'int64'
19
+ | 'string';
20
+
21
+ /**
22
+ * File open/create modes
23
+ */
24
+ export type FileMode =
25
+ | 'r' // Read-only
26
+ | 'w' // Read-write
27
+ | 'c' // Create (no clobber)
28
+ | 'c!'; // Create (clobber/overwrite)
29
+
30
+ /**
31
+ * NetCDF file formats
32
+ */
33
+ export type FileFormat =
34
+ | 'classic' // Classic NetCDF format
35
+ | 'classic64' // 64-bit offset format
36
+ | 'nodenetcdf' // NetCDF-4 format
37
+ | 'nodenetcdfclassic'; // NetCDF-4 classic model
38
+
39
+ /**
40
+ * Endianness options
41
+ */
42
+ export type Endianness = 'little' | 'big' | 'native';
43
+
44
+ /**
45
+ * Checksum modes
46
+ */
47
+ export type ChecksumMode = 'none' | 'fletcher32';
48
+
49
+ /**
50
+ * Chunk modes
51
+ */
52
+ export type ChunkMode = 'contiguous' | 'chunked';
53
+
54
+ /**
55
+ * Fill modes
56
+ */
57
+ export type FillMode = 'fill' | 'nofill';
58
+
59
+ /**
60
+ * Represents a NetCDF attribute
61
+ */
62
+ export class Attribute {
63
+ /**
64
+ * The name of the attribute
65
+ */
66
+ name: string;
67
+
68
+ /**
69
+ * The value of the attribute
70
+ */
71
+ value: any;
72
+
73
+ /**
74
+ * Delete this attribute
75
+ */
76
+ delete(): void;
77
+
78
+ /**
79
+ * Inspect the attribute
80
+ */
81
+ inspect(): string;
82
+
83
+ /**
84
+ * Convert the attribute to a JSON-serializable object
85
+ */
86
+ toJSON(): { name: string; value: any };
87
+ }
88
+
89
+ /**
90
+ * Represents a NetCDF dimension
91
+ */
92
+ export class Dimension {
93
+ /**
94
+ * The dimension ID
95
+ */
96
+ readonly id: number;
97
+
98
+ /**
99
+ * The length of the dimension
100
+ */
101
+ readonly length: number;
102
+
103
+ /**
104
+ * The name of the dimension
105
+ */
106
+ name: string;
107
+
108
+ /**
109
+ * Inspect the dimension
110
+ */
111
+ inspect(): string;
112
+
113
+ /**
114
+ * Convert the dimension to a JSON-serializable object
115
+ */
116
+ toJSON(): { id: number; name: string; length: number };
117
+ }
118
+
119
+ /**
120
+ * Represents a NetCDF variable
121
+ */
122
+ export class Variable {
123
+ /**
124
+ * The variable ID
125
+ */
126
+ readonly id: number;
127
+
128
+ /**
129
+ * The data type of the variable
130
+ */
131
+ readonly type: NetCDFDataType;
132
+
133
+ /**
134
+ * The dimensions of the variable
135
+ */
136
+ readonly dimensions: Dimension[];
137
+
138
+ /**
139
+ * The attributes of the variable
140
+ */
141
+ readonly attributes: { [name: string]: Attribute };
142
+
143
+ /**
144
+ * The name of the variable
145
+ */
146
+ name: string;
147
+
148
+ /**
149
+ * The endianness of the variable
150
+ */
151
+ endianness: Endianness;
152
+
153
+ /**
154
+ * The checksum mode
155
+ */
156
+ checksumMode: ChecksumMode;
157
+
158
+ /**
159
+ * The chunk mode
160
+ */
161
+ chunkMode: ChunkMode;
162
+
163
+ /**
164
+ * The chunk sizes
165
+ */
166
+ chunkSizes: number[];
167
+
168
+ /**
169
+ * The fill mode
170
+ */
171
+ fillMode: FillMode;
172
+
173
+ /**
174
+ * The fill value
175
+ */
176
+ fillValue: any;
177
+
178
+ /**
179
+ * Whether compression shuffle is enabled
180
+ */
181
+ compressionShuffle: boolean;
182
+
183
+ /**
184
+ * Whether compression deflate is enabled
185
+ */
186
+ compressionDeflate: boolean;
187
+
188
+ /**
189
+ * The compression level (0-9)
190
+ */
191
+ compressionLevel: number;
192
+
193
+ /**
194
+ * Read the entire variable
195
+ */
196
+ read(): any;
197
+
198
+ /**
199
+ * Read a slice of the variable
200
+ * @param start - Starting indices for each dimension
201
+ * @param count - Number of elements to read in each dimension
202
+ */
203
+ readSlice(start: number[], count: number[]): any;
204
+
205
+ /**
206
+ * Read a strided slice of the variable
207
+ * @param start - Starting indices for each dimension
208
+ * @param count - Number of elements to read in each dimension
209
+ * @param stride - Stride for each dimension
210
+ */
211
+ readStridedSlice(start: number[], count: number[], stride: number[]): any;
212
+
213
+ /**
214
+ * Write data to the entire variable
215
+ * @param data - Data to write
216
+ */
217
+ write(data: any): void;
218
+
219
+ /**
220
+ * Write data to a slice of the variable
221
+ * @param start - Starting indices for each dimension
222
+ * @param count - Number of elements to write in each dimension
223
+ * @param data - Data to write
224
+ */
225
+ writeSlice(start: number[], count: number[], data: any): void;
226
+
227
+ /**
228
+ * Write data to a strided slice of the variable
229
+ * @param start - Starting indices for each dimension
230
+ * @param count - Number of elements to write in each dimension
231
+ * @param stride - Stride for each dimension
232
+ * @param data - Data to write
233
+ */
234
+ writeStridedSlice(start: number[], count: number[], stride: number[], data: any): void;
235
+
236
+ /**
237
+ * Add an attribute to the variable
238
+ * @param name - Attribute name
239
+ * @param type - Data type
240
+ * @param value - Attribute value
241
+ */
242
+ addAttribute(name: string, type: NetCDFDataType, value: any): Attribute;
243
+
244
+ /**
245
+ * Inspect the variable
246
+ */
247
+ inspect(): string;
248
+
249
+ /**
250
+ * Convert the variable to a JSON-serializable object (recursively serializes dimensions and attributes)
251
+ */
252
+ toJSON(): {
253
+ id: number;
254
+ name: string;
255
+ type: NetCDFDataType;
256
+ dimensions: Array<{ id: number; name: string; length: number }>;
257
+ attributes: { [name: string]: { name: string; value: any } };
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Represents a NetCDF group
263
+ */
264
+ export class Group {
265
+ /**
266
+ * The group ID
267
+ */
268
+ readonly id: number;
269
+
270
+ /**
271
+ * Variables in this group
272
+ */
273
+ readonly variables: { [name: string]: Variable };
274
+
275
+ /**
276
+ * Dimensions in this group
277
+ */
278
+ readonly dimensions: { [name: string]: Dimension };
279
+
280
+ /**
281
+ * The unlimited dimension in this group
282
+ */
283
+ readonly unlimited: Dimension | null;
284
+
285
+ /**
286
+ * Attributes in this group
287
+ */
288
+ readonly attributes: { [name: string]: Attribute };
289
+
290
+ /**
291
+ * Subgroups in this group
292
+ */
293
+ readonly subgroups: { [name: string]: Group };
294
+
295
+ /**
296
+ * The name of the group
297
+ */
298
+ readonly name: string;
299
+
300
+ /**
301
+ * The full name (path) of the group
302
+ */
303
+ readonly fullname: string;
304
+
305
+ /**
306
+ * Add an attribute to the group
307
+ * @param name - Attribute name
308
+ * @param type - Data type
309
+ * @param value - Attribute value
310
+ */
311
+ addAttribute(name: string, type: NetCDFDataType, value: any): Attribute;
312
+
313
+ /**
314
+ * Add a dimension to the group
315
+ * @param name - Dimension name
316
+ * @param length - Dimension length (0 for unlimited)
317
+ */
318
+ addDimension(name: string, length: number): Dimension;
319
+
320
+ /**
321
+ * Add a subgroup to the group
322
+ * @param name - Subgroup name
323
+ */
324
+ addSubgroup(name: string): Group;
325
+
326
+ /**
327
+ * Add a variable to the group
328
+ * @param name - Variable name
329
+ * @param type - Data type
330
+ * @param dimensions - Array of dimension names or Dimension objects
331
+ */
332
+ addVariable(name: string, type: NetCDFDataType, dimensions: (string | Dimension)[]): Variable;
333
+
334
+ /**
335
+ * Inspect the group
336
+ */
337
+ inspect(): string;
338
+
339
+ /**
340
+ * Convert the group to a JSON-serializable object (recursively serializes all children: dimensions, variables, attributes, subgroups)
341
+ */
342
+ toJSON(): {
343
+ id: number;
344
+ name: string;
345
+ fullname: string;
346
+ dimensions: { [name: string]: { id: number; name: string; length: number } };
347
+ variables: { [name: string]: any };
348
+ attributes: { [name: string]: { name: string; value: any } };
349
+ subgroups: { [name: string]: any };
350
+ };
351
+ }
352
+
353
+ /**
354
+ * Represents a NetCDF file
355
+ */
356
+ export class File {
357
+ /**
358
+ * The root group of the file
359
+ */
360
+ readonly root: Group;
361
+
362
+ /**
363
+ * Open or create a NetCDF file
364
+ * @param filename - Path to the file
365
+ * @param mode - File mode ('r', 'w', 'c', 'c!')
366
+ * @param format - File format (optional, defaults to 'nodenetcdf')
367
+ */
368
+ constructor(filename: string, mode: FileMode, format?: FileFormat);
369
+
370
+ /**
371
+ * Synchronize the file to disk
372
+ */
373
+ sync(): void;
374
+
375
+ /**
376
+ * Close the file
377
+ */
378
+ close(): void;
379
+
380
+ /**
381
+ * Inspect the file
382
+ */
383
+ inspect(): string;
384
+
385
+ /**
386
+ * Convert the file to a JSON-serializable object (serializes the entire file structure via root group)
387
+ */
388
+ toJSON(): any;
389
+ }
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "nodenetcdf",
3
- "version": "4.9.3",
3
+ "version": "4.9.32",
4
4
  "description": "Read and write NodeNetCDF files",
5
5
  "main": "./build/Release/nodenetcdf.node",
6
+ "types": "./index.d.ts",
6
7
  "scripts": {
7
8
  "preinstall": "node scripts/setup-vcpkg.js",
8
9
  "install": "node scripts/verify-build-deps.js && node-gyp configure build",
9
10
  "postinstall": "node scripts/copy-deps.js",
10
- "test": "mocha",
11
+ "test": "npm run test:types && mocha",
12
+ "test:types": "node scripts/test-types.js",
11
13
  "verify-deps": "node scripts/verify-build-deps.js"
12
14
  },
13
15
  "author": {
@@ -30,6 +32,8 @@
30
32
  },
31
33
  "devDependencies": {
32
34
  "chai": "^6.2.0",
33
- "mocha": "^11.7.4"
35
+ "mocha": "^11.7.4",
36
+ "typescript": "^5.7.2",
37
+ "@types/node": "^22.10.5"
34
38
  }
35
39
  }
@@ -0,0 +1,15 @@
1
+ const { execSync } = require('child_process');
2
+
3
+ console.log('\nRunning TypeScript type checking...\n');
4
+
5
+ try {
6
+ execSync('tsc test/typescript-test.ts --noEmit --skipLibCheck', {
7
+ stdio: 'inherit',
8
+ cwd: process.cwd()
9
+ });
10
+ console.log('\n✅ TypeScript type checking passed!\n');
11
+ process.exit(0);
12
+ } catch (error) {
13
+ console.log('\n❌ TypeScript type checking failed!\n');
14
+ process.exit(1);
15
+ }
package/src/Attribute.cpp CHANGED
@@ -46,6 +46,7 @@ void Attribute::Init(v8::Local<v8::Object> exports)
46
46
  tpl->InstanceTemplate()->SetInternalFieldCount(1);
47
47
  NODE_SET_PROTOTYPE_METHOD(tpl, "delete", Attribute::Delete);
48
48
  NODE_SET_PROTOTYPE_METHOD(tpl, "inspect", Attribute::Inspect);
49
+ NODE_SET_PROTOTYPE_METHOD(tpl, "toJSON", Attribute::ToJSON);
49
50
  tpl->InstanceTemplate()->SetAccessor(
50
51
  v8::String::NewFromUtf8(isolate, "name", v8::NewStringType::kNormal).ToLocalChecked(), Attribute::GetName,
51
52
  Attribute::SetName);
@@ -331,4 +332,57 @@ void Attribute::Inspect(const v8::FunctionCallbackInfo<v8::Value> &args)
331
332
  args.GetReturnValue().Set(
332
333
  v8::String::NewFromUtf8(isolate, "[object Attribute]", v8::NewStringType::kNormal).ToLocalChecked());
333
334
  }
335
+
336
+ void Attribute::ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args)
337
+ {
338
+ v8::Isolate *isolate = args.GetIsolate();
339
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
340
+ const auto *obj = node::ObjectWrap::Unwrap<Attribute>(args.Holder());
341
+
342
+ // Use internalized strings for better performance
343
+ v8::Local<v8::String> name_str = v8::String::NewFromUtf8Literal(isolate, "name");
344
+ v8::Local<v8::String> value_str = v8::String::NewFromUtf8Literal(isolate, "value");
345
+
346
+ v8::Local<v8::Object> json = v8::Object::New(isolate);
347
+
348
+ // Add name
349
+ (void)json->CreateDataProperty(context, name_str,
350
+ v8::String::NewFromUtf8(isolate, obj->name.c_str(), v8::NewStringType::kInternalized).ToLocalChecked());
351
+
352
+ // Add value - get from the object's value property
353
+ // Use a TryCatch to handle errors when getting the value
354
+ v8::TryCatch try_catch(isolate);
355
+ v8::MaybeLocal<v8::Value> maybeValue = args.Holder()->Get(context, value_str);
356
+ v8::Local<v8::Value> value;
357
+
358
+ if (!maybeValue.ToLocal(&value) || try_catch.HasCaught())
359
+ {
360
+ // If getting the value failed or threw an exception, clear the exception
361
+ // and set value to null instead of crashing
362
+ if (try_catch.HasCaught())
363
+ {
364
+ try_catch.Reset();
365
+ }
366
+ value = v8::Null(isolate);
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
383
+
384
+ (void)json->CreateDataProperty(context, value_str, value);
385
+
386
+ args.GetReturnValue().Set(json);
387
+ }
334
388
  } // namespace nodenetcdfjs
package/src/Attribute.h CHANGED
@@ -34,6 +34,7 @@ class Attribute : public node::ObjectWrap
34
34
  static void SetValue(v8::Local<v8::String> property, v8::Local<v8::Value> val,
35
35
  const v8::PropertyCallbackInfo<void> &info);
36
36
  static void Inspect(const v8::FunctionCallbackInfo<v8::Value> &args);
37
+ static void ToJSON(const v8::FunctionCallbackInfo<v8::Value> &args);
37
38
 
38
39
  std::string name{};
39
40
  int var_id{-1};