@mitre/hdf-utilities 2.0.0
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/LICENSE.md +55 -0
- package/README.md +403 -0
- package/dist/csv/index.d.ts +100 -0
- package/dist/csv/index.d.ts.map +1 -0
- package/dist/csv/index.js +251 -0
- package/dist/csv/index.js.map +1 -0
- package/dist/hash/index.d.ts +95 -0
- package/dist/hash/index.d.ts.map +1 -0
- package/dist/hash/index.js +118 -0
- package/dist/hash/index.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/json/index.d.ts +32 -0
- package/dist/json/index.d.ts.map +1 -0
- package/dist/json/index.js +61 -0
- package/dist/json/index.js.map +1 -0
- package/dist/object/index.d.ts +41 -0
- package/dist/object/index.d.ts.map +1 -0
- package/dist/object/index.js +70 -0
- package/dist/object/index.js.map +1 -0
- package/dist/string/index.d.ts +50 -0
- package/dist/string/index.d.ts.map +1 -0
- package/dist/string/index.js +62 -0
- package/dist/string/index.js.map +1 -0
- package/dist/xml/index.d.ts +86 -0
- package/dist/xml/index.d.ts.map +1 -0
- package/dist/xml/index.js +187 -0
- package/dist/xml/index.js.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSV parsing and generation utilities using d3-dsv
|
|
3
|
+
*
|
|
4
|
+
* SECURITY WARNING: CSV files opened in Excel/LibreOffice may execute formulas.
|
|
5
|
+
* Use sanitization options when exporting data that may contain user-controlled content.
|
|
6
|
+
*/
|
|
7
|
+
import { dsvFormat } from 'd3-dsv';
|
|
8
|
+
export { extractColumn as extractCsvColumn, findRows as findCsvRows, } from '../object/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Default options for parsing CSV with headers
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_PARSE_OPTIONS = {
|
|
13
|
+
header: true,
|
|
14
|
+
skipEmptyLines: true,
|
|
15
|
+
transformHeader: undefined,
|
|
16
|
+
dynamicTyping: false,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Default options for parsing CSV without headers
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_PARSE_ARRAY_OPTIONS = {
|
|
22
|
+
header: false,
|
|
23
|
+
skipEmptyLines: true,
|
|
24
|
+
dynamicTyping: false,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Default options for building CSV
|
|
28
|
+
*/
|
|
29
|
+
const DEFAULT_BUILD_OPTIONS = {
|
|
30
|
+
header: true,
|
|
31
|
+
newline: '\n',
|
|
32
|
+
skipEmptyLines: true,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Validate CSV quoting — throws if unclosed quotes are found
|
|
36
|
+
*/
|
|
37
|
+
function validateQuoting(csv) {
|
|
38
|
+
let inQuotes = false;
|
|
39
|
+
let row = 0;
|
|
40
|
+
for (let i = 0; i < csv.length; i++) {
|
|
41
|
+
if (csv[i] === '"') {
|
|
42
|
+
if (inQuotes && i + 1 < csv.length && csv[i + 1] === '"') {
|
|
43
|
+
i++; // skip escaped quote ""
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
inQuotes = !inQuotes;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else if (csv[i] === '\n' && !inQuotes) {
|
|
50
|
+
row++;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (inQuotes) {
|
|
54
|
+
throw new Error(`CSV parsing failed: Row ${row}: Unclosed quote`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert string value to number or boolean when appropriate
|
|
59
|
+
*/
|
|
60
|
+
function dynamicTypeConvert(value) {
|
|
61
|
+
if (value === '')
|
|
62
|
+
return value;
|
|
63
|
+
if (value === 'true')
|
|
64
|
+
return true;
|
|
65
|
+
if (value === 'false')
|
|
66
|
+
return false;
|
|
67
|
+
const num = Number(value);
|
|
68
|
+
if (!isNaN(num) && value.trim() !== '')
|
|
69
|
+
return num;
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Parse CSV string into array of objects with headers as keys
|
|
74
|
+
* @param csv - CSV string to parse
|
|
75
|
+
* @param options - Optional parse configuration
|
|
76
|
+
* @returns Array of objects representing rows
|
|
77
|
+
* @throws Error if parsing fails
|
|
78
|
+
*/
|
|
79
|
+
export function parseCsv(csv, options) {
|
|
80
|
+
if (options?.maxSize !== undefined && csv.length > options.maxSize) {
|
|
81
|
+
throw new Error(`Input exceeds maximum allowed size: ${csv.length} bytes exceeds limit of ${options.maxSize} bytes`);
|
|
82
|
+
}
|
|
83
|
+
const opts = { ...DEFAULT_PARSE_OPTIONS, ...options };
|
|
84
|
+
const trimmed = csv.trim();
|
|
85
|
+
validateQuoting(trimmed);
|
|
86
|
+
const dsv = dsvFormat(opts.delimiter ?? ',');
|
|
87
|
+
const parsed = dsv.parse(trimmed);
|
|
88
|
+
const { columns } = parsed;
|
|
89
|
+
// Pre-compute transformed headers
|
|
90
|
+
const headers = opts.transformHeader
|
|
91
|
+
? columns.map((col, i) => opts.transformHeader(col, i))
|
|
92
|
+
: columns;
|
|
93
|
+
let rows = parsed.map((row) => {
|
|
94
|
+
const obj = {};
|
|
95
|
+
columns.forEach((col, i) => {
|
|
96
|
+
let value = row[col] ?? '';
|
|
97
|
+
if (opts.dynamicTyping && typeof value === 'string') {
|
|
98
|
+
value = dynamicTypeConvert(value);
|
|
99
|
+
}
|
|
100
|
+
const key = headers[i];
|
|
101
|
+
if (key !== undefined) {
|
|
102
|
+
obj[key] = value;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
return obj;
|
|
106
|
+
});
|
|
107
|
+
if (opts.skipEmptyLines) {
|
|
108
|
+
rows = rows.filter((row) => Object.values(row).some((v) => v !== '' && v !== null && v !== undefined));
|
|
109
|
+
}
|
|
110
|
+
return rows;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Parse CSV string into array of arrays without treating first row as headers
|
|
114
|
+
* @param csv - CSV string to parse
|
|
115
|
+
* @param options - Optional parse configuration
|
|
116
|
+
* @returns Array of arrays representing rows
|
|
117
|
+
* @throws Error if parsing fails
|
|
118
|
+
*/
|
|
119
|
+
export function parseCsvArray(csv, options) {
|
|
120
|
+
if (options?.maxSize !== undefined && csv.length > options.maxSize) {
|
|
121
|
+
throw new Error(`Input exceeds maximum allowed size: ${csv.length} bytes exceeds limit of ${options.maxSize} bytes`);
|
|
122
|
+
}
|
|
123
|
+
const opts = { ...DEFAULT_PARSE_ARRAY_OPTIONS, ...options };
|
|
124
|
+
const trimmed = csv.trim();
|
|
125
|
+
validateQuoting(trimmed);
|
|
126
|
+
const dsv = dsvFormat(opts.delimiter ?? ',');
|
|
127
|
+
let rows = dsv.parseRows(trimmed);
|
|
128
|
+
if (opts.skipEmptyLines) {
|
|
129
|
+
rows = rows.filter((row) => !(row.length === 1 && row[0] === ''));
|
|
130
|
+
}
|
|
131
|
+
return rows;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build CSV string from array of objects
|
|
135
|
+
*
|
|
136
|
+
* SECURITY: Set sanitize=true when data may contain user-controlled content
|
|
137
|
+
* to prevent CSV formula injection attacks in Excel/LibreOffice.
|
|
138
|
+
*
|
|
139
|
+
* @param data - Array of objects to convert to CSV
|
|
140
|
+
* @param options - Optional build configuration and sanitize flag
|
|
141
|
+
* @returns CSV string
|
|
142
|
+
*/
|
|
143
|
+
export function buildCsv(data, options) {
|
|
144
|
+
const { sanitize, ...buildOpts } = options || {};
|
|
145
|
+
const opts = { ...DEFAULT_BUILD_OPTIONS, ...buildOpts };
|
|
146
|
+
if (data.length === 0)
|
|
147
|
+
return '';
|
|
148
|
+
let processedData = data;
|
|
149
|
+
if (sanitize) {
|
|
150
|
+
processedData = data.map((row) => sanitizeCsvObject(row));
|
|
151
|
+
}
|
|
152
|
+
const dsv = dsvFormat(opts.delimiter ?? ',');
|
|
153
|
+
let result;
|
|
154
|
+
if (opts.header === false) {
|
|
155
|
+
const rows = processedData.map((row) => Object.values(row).map(String));
|
|
156
|
+
result = dsv.formatRows(rows);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
result = dsv.format(processedData);
|
|
160
|
+
}
|
|
161
|
+
if (opts.newline && opts.newline !== '\n') {
|
|
162
|
+
result = result.replace(/\n/g, opts.newline);
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build CSV string from array of arrays
|
|
168
|
+
*
|
|
169
|
+
* SECURITY: Set sanitize=true when data may contain user-controlled content
|
|
170
|
+
* to prevent CSV formula injection attacks in Excel/LibreOffice.
|
|
171
|
+
*
|
|
172
|
+
* @param data - Array of arrays to convert to CSV
|
|
173
|
+
* @param options - Optional build configuration and sanitize flag
|
|
174
|
+
* @returns CSV string
|
|
175
|
+
*/
|
|
176
|
+
export function buildCsvArray(data, options) {
|
|
177
|
+
const { sanitize, ...buildOpts } = options || {};
|
|
178
|
+
const opts = { ...DEFAULT_BUILD_OPTIONS, header: false, ...buildOpts };
|
|
179
|
+
if (data.length === 0)
|
|
180
|
+
return '';
|
|
181
|
+
let processedData = data;
|
|
182
|
+
if (sanitize) {
|
|
183
|
+
processedData = data.map((row) => sanitizeCsvArray(row));
|
|
184
|
+
}
|
|
185
|
+
const dsv = dsvFormat(opts.delimiter ?? ',');
|
|
186
|
+
let result = dsv.formatRows(processedData);
|
|
187
|
+
if (opts.newline && opts.newline !== '\n') {
|
|
188
|
+
result = result.replace(/\n/g, opts.newline);
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Validate CSV format
|
|
194
|
+
* @param csv - CSV string to validate
|
|
195
|
+
* @returns True if valid CSV, false otherwise
|
|
196
|
+
*/
|
|
197
|
+
export function isValidCsv(csv) {
|
|
198
|
+
if (!csv || csv.trim().length === 0)
|
|
199
|
+
return false;
|
|
200
|
+
const trimmed = csv.trim();
|
|
201
|
+
// CSV must have at least one delimiter (comma) to be considered CSV structure
|
|
202
|
+
if (!trimmed.includes(','))
|
|
203
|
+
return false;
|
|
204
|
+
try {
|
|
205
|
+
validateQuoting(trimmed);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Sanitize a single CSV value to prevent formula injection
|
|
214
|
+
*
|
|
215
|
+
* Prefixes values starting with =, +, -, @, |, or % with a single quote
|
|
216
|
+
* to prevent Excel/LibreOffice from interpreting them as formulas.
|
|
217
|
+
*
|
|
218
|
+
* @param value - Value to sanitize
|
|
219
|
+
* @returns Sanitized value
|
|
220
|
+
*/
|
|
221
|
+
export function sanitizeCsvValue(value) {
|
|
222
|
+
const str = String(value);
|
|
223
|
+
// Check if string starts with formula trigger characters
|
|
224
|
+
if (/^[=+\-@|%]/.test(str)) {
|
|
225
|
+
return `'${str}`;
|
|
226
|
+
}
|
|
227
|
+
return str;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Sanitize all values in an array to prevent formula injection
|
|
231
|
+
*
|
|
232
|
+
* @param values - Array of values to sanitize
|
|
233
|
+
* @returns Array with sanitized values
|
|
234
|
+
*/
|
|
235
|
+
export function sanitizeCsvArray(values) {
|
|
236
|
+
return values.map(sanitizeCsvValue);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Sanitize all values in an object to prevent formula injection
|
|
240
|
+
*
|
|
241
|
+
* @param obj - Object with values to sanitize
|
|
242
|
+
* @returns New object with sanitized values
|
|
243
|
+
*/
|
|
244
|
+
export function sanitizeCsvObject(obj) {
|
|
245
|
+
const sanitized = {};
|
|
246
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
247
|
+
sanitized[key] = sanitizeCsvValue(value);
|
|
248
|
+
}
|
|
249
|
+
return sanitized;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/csv/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash utilities for HDF content
|
|
3
|
+
* Provides cryptographic hashing functions for content identification and integrity verification
|
|
4
|
+
* Uses the Web Crypto API (globalThis.crypto.subtle) for browser and Node.js compatibility
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Supported hash algorithms
|
|
8
|
+
*/
|
|
9
|
+
export type HashAlgorithm = 'sha256' | 'sha512';
|
|
10
|
+
/**
|
|
11
|
+
* Supported output encodings
|
|
12
|
+
*/
|
|
13
|
+
export type HashEncoding = 'hex' | 'base64';
|
|
14
|
+
/**
|
|
15
|
+
* Options for hash generation
|
|
16
|
+
*/
|
|
17
|
+
export interface HashOptions {
|
|
18
|
+
/** Hash algorithm (default: 'sha256') */
|
|
19
|
+
algorithm?: HashAlgorithm;
|
|
20
|
+
/** Output encoding (default: 'hex') */
|
|
21
|
+
encoding?: HashEncoding;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate a hash of the given data
|
|
25
|
+
*
|
|
26
|
+
* @param data - String data to hash
|
|
27
|
+
* @param options - Hash generation options
|
|
28
|
+
* @returns Hex-encoded hash string
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const hash = await generateHash('hello world');
|
|
33
|
+
* // Returns: 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateHash(data: string, options?: HashOptions): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Generate a SHA-256 hash (recommended for most use cases)
|
|
39
|
+
*
|
|
40
|
+
* @param data - String data to hash
|
|
41
|
+
* @returns Hex-encoded SHA-256 hash
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const hash = await sha256('hello world');
|
|
46
|
+
* // Returns: 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function sha256(data: string): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Generate a SHA-512 hash (enhanced security for sensitive data)
|
|
52
|
+
*
|
|
53
|
+
* @param data - String data to hash
|
|
54
|
+
* @returns Hex-encoded SHA-512 hash
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const hash = await sha512('hello world');
|
|
59
|
+
* // Returns: '309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f'
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function sha512(data: string): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Generate a hash of an object by stringifying it first
|
|
65
|
+
* Useful for hashing HDF control objects or other structured data
|
|
66
|
+
*
|
|
67
|
+
* @param obj - Object to hash
|
|
68
|
+
* @param options - Hash generation options
|
|
69
|
+
* @returns Hex-encoded hash string
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const control = { id: 'V-12345', title: 'Test Control' };
|
|
74
|
+
* const hash = await hashObject(control);
|
|
75
|
+
* // Returns hash of the JSON-stringified object
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function hashObject(obj: unknown, options?: HashOptions): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Verify that data matches a given hash
|
|
81
|
+
*
|
|
82
|
+
* @param data - String data to verify
|
|
83
|
+
* @param expectedHash - Expected hash value
|
|
84
|
+
* @param options - Hash generation options (must match hash generation)
|
|
85
|
+
* @returns True if data matches the hash
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const data = 'hello world';
|
|
90
|
+
* const hash = await sha256(data);
|
|
91
|
+
* const isValid = await verifyHash(data, hash); // true
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function verifyHash(data: string, expectedHash: string, options?: HashOptions): Promise<boolean>;
|
|
95
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hash/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AA4BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM3F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAIzF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CAGlB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash utilities for HDF content
|
|
3
|
+
* Provides cryptographic hashing functions for content identification and integrity verification
|
|
4
|
+
* Uses the Web Crypto API (globalThis.crypto.subtle) for browser and Node.js compatibility
|
|
5
|
+
*/
|
|
6
|
+
/** Map our algorithm names to Web Crypto algorithm identifiers */
|
|
7
|
+
const ALGORITHM_MAP = {
|
|
8
|
+
sha256: 'SHA-256',
|
|
9
|
+
sha512: 'SHA-512',
|
|
10
|
+
};
|
|
11
|
+
/** Convert an ArrayBuffer to a hex string */
|
|
12
|
+
function bufferToHex(buffer) {
|
|
13
|
+
const bytes = new Uint8Array(buffer);
|
|
14
|
+
let hex = '';
|
|
15
|
+
for (const b of bytes) {
|
|
16
|
+
hex += b.toString(16).padStart(2, '0');
|
|
17
|
+
}
|
|
18
|
+
return hex;
|
|
19
|
+
}
|
|
20
|
+
/** Convert an ArrayBuffer to a base64 string */
|
|
21
|
+
function bufferToBase64(buffer) {
|
|
22
|
+
const bytes = new Uint8Array(buffer);
|
|
23
|
+
let binary = '';
|
|
24
|
+
for (const b of bytes) {
|
|
25
|
+
binary += String.fromCharCode(b);
|
|
26
|
+
}
|
|
27
|
+
return btoa(binary);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate a hash of the given data
|
|
31
|
+
*
|
|
32
|
+
* @param data - String data to hash
|
|
33
|
+
* @param options - Hash generation options
|
|
34
|
+
* @returns Hex-encoded hash string
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const hash = await generateHash('hello world');
|
|
39
|
+
* // Returns: 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export async function generateHash(data, options = {}) {
|
|
43
|
+
const { algorithm = 'sha256', encoding = 'hex' } = options;
|
|
44
|
+
const webAlgorithm = ALGORITHM_MAP[algorithm];
|
|
45
|
+
const encoded = new TextEncoder().encode(data);
|
|
46
|
+
const hashBuffer = await globalThis.crypto.subtle.digest(webAlgorithm, encoded);
|
|
47
|
+
return encoding === 'base64' ? bufferToBase64(hashBuffer) : bufferToHex(hashBuffer);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Generate a SHA-256 hash (recommended for most use cases)
|
|
51
|
+
*
|
|
52
|
+
* @param data - String data to hash
|
|
53
|
+
* @returns Hex-encoded SHA-256 hash
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const hash = await sha256('hello world');
|
|
58
|
+
* // Returns: 'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export async function sha256(data) {
|
|
62
|
+
return generateHash(data, { algorithm: 'sha256' });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate a SHA-512 hash (enhanced security for sensitive data)
|
|
66
|
+
*
|
|
67
|
+
* @param data - String data to hash
|
|
68
|
+
* @returns Hex-encoded SHA-512 hash
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const hash = await sha512('hello world');
|
|
73
|
+
* // Returns: '309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f'
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export async function sha512(data) {
|
|
77
|
+
return generateHash(data, { algorithm: 'sha512' });
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generate a hash of an object by stringifying it first
|
|
81
|
+
* Useful for hashing HDF control objects or other structured data
|
|
82
|
+
*
|
|
83
|
+
* @param obj - Object to hash
|
|
84
|
+
* @param options - Hash generation options
|
|
85
|
+
* @returns Hex-encoded hash string
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* const control = { id: 'V-12345', title: 'Test Control' };
|
|
90
|
+
* const hash = await hashObject(control);
|
|
91
|
+
* // Returns hash of the JSON-stringified object
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export async function hashObject(obj, options = {}) {
|
|
95
|
+
// JSON.stringify returns undefined for undefined, so handle it explicitly
|
|
96
|
+
const stringified = obj === undefined ? 'undefined' : JSON.stringify(obj);
|
|
97
|
+
return generateHash(stringified, options);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Verify that data matches a given hash
|
|
101
|
+
*
|
|
102
|
+
* @param data - String data to verify
|
|
103
|
+
* @param expectedHash - Expected hash value
|
|
104
|
+
* @param options - Hash generation options (must match hash generation)
|
|
105
|
+
* @returns True if data matches the hash
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const data = 'hello world';
|
|
110
|
+
* const hash = await sha256(data);
|
|
111
|
+
* const isValid = await verifyHash(data, hash); // true
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export async function verifyHash(data, expectedHash, options = {}) {
|
|
115
|
+
const actualHash = await generateHash(data, options);
|
|
116
|
+
return actualHash === expectedHash;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hash/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsBH,kEAAkE;AAClE,MAAM,aAAa,GAAkC;IACnD,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,6CAA6C;AAC7C,SAAS,WAAW,CAAC,MAAmB;IACtC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gDAAgD;AAChD,SAAS,cAAc,CAAC,MAAmB;IACzC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,UAAuB,EAAE;IACxE,MAAM,EAAE,SAAS,GAAG,QAAQ,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAC3D,MAAM,YAAY,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAChF,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AACtF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY;IACvC,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAY;IACvC,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAY,EAAE,UAAuB,EAAE;IACtE,0EAA0E;IAC1E,MAAM,WAAW,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC1E,OAAO,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,YAAoB,EACpB,UAAuB,EAAE;IAEzB,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACrD,OAAO,UAAU,KAAK,YAAY,CAAC;AACrC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mitre/hdf-utilities
|
|
3
|
+
* Utility functions for HDF libraries
|
|
4
|
+
*/
|
|
5
|
+
export { parseJSON, stringifyJSON, isValidJSON, findJsonValues, type StringifyOptions } from './json/index.js';
|
|
6
|
+
export { generateHash, sha256, sha512, hashObject, verifyHash, type HashAlgorithm, type HashEncoding, type HashOptions, } from './hash/index.js';
|
|
7
|
+
export { parseXml, buildXml, isValidXml, parseXmlWithArrays, extractTextFromXml, findXmlValues, } from './xml/index.js';
|
|
8
|
+
export { parseCsv, parseCsvArray, buildCsv, buildCsvArray, isValidCsv, sanitizeCsvValue, sanitizeCsvArray, sanitizeCsvObject, extractCsvColumn, findCsvRows, type CsvParseOptions, type CsvBuildOptions, } from './csv/index.js';
|
|
9
|
+
export { findValuesByKey, extractColumn, findRows } from './object/index.js';
|
|
10
|
+
export { stripHtml, parseTimestamp } from './string/index.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAG/G,OAAO,EACL,YAAY,EACZ,MAAM,EACN,MAAM,EACN,UAAU,EACV,UAAU,EACV,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,GACjB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7E,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @mitre/hdf-utilities
|
|
3
|
+
* Utility functions for HDF libraries
|
|
4
|
+
*/
|
|
5
|
+
// JSON utilities
|
|
6
|
+
export { parseJSON, stringifyJSON, isValidJSON, findJsonValues } from './json/index.js';
|
|
7
|
+
// Hash utilities
|
|
8
|
+
export { generateHash, sha256, sha512, hashObject, verifyHash, } from './hash/index.js';
|
|
9
|
+
// XML utilities
|
|
10
|
+
export { parseXml, buildXml, isValidXml, parseXmlWithArrays, extractTextFromXml, findXmlValues, } from './xml/index.js';
|
|
11
|
+
// CSV utilities
|
|
12
|
+
export { parseCsv, parseCsvArray, buildCsv, buildCsvArray, isValidCsv, sanitizeCsvValue, sanitizeCsvArray, sanitizeCsvObject, extractCsvColumn, findCsvRows, } from './csv/index.js';
|
|
13
|
+
// Object utilities (generic traversal)
|
|
14
|
+
export { findValuesByKey, extractColumn, findRows } from './object/index.js';
|
|
15
|
+
// String utilities
|
|
16
|
+
export { stripHtml, parseTimestamp } from './string/index.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iBAAiB;AACjB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAyB,MAAM,iBAAiB,CAAC;AAE/G,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,MAAM,EACN,MAAM,EACN,UAAU,EACV,UAAU,GAIX,MAAM,iBAAiB,CAAC;AAEzB,gBAAgB;AAChB,OAAO,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAC;AAExB,gBAAgB;AAChB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,GAGZ,MAAM,gBAAgB,CAAC;AAExB,uCAAuC;AACvC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7E,mBAAmB;AACnB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export { findValuesByKey as findJsonValues } from '../object/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Options for JSON stringification
|
|
4
|
+
*/
|
|
5
|
+
export interface StringifyOptions {
|
|
6
|
+
/** Enable pretty printing with indentation */
|
|
7
|
+
pretty?: boolean;
|
|
8
|
+
/** Number of spaces for indentation (default: 2) */
|
|
9
|
+
indent?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Safely parse a JSON string
|
|
13
|
+
* @param input - JSON string to parse
|
|
14
|
+
* @returns Parsed JSON value
|
|
15
|
+
* @throws Error if input is not valid JSON
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseJSON<T = unknown>(input: string): T;
|
|
18
|
+
/**
|
|
19
|
+
* Safely stringify a value to JSON
|
|
20
|
+
* @param value - Value to stringify
|
|
21
|
+
* @param options - Stringification options
|
|
22
|
+
* @returns JSON string
|
|
23
|
+
* @throws Error if value contains circular references or cannot be stringified
|
|
24
|
+
*/
|
|
25
|
+
export declare function stringifyJSON(value: unknown, options?: StringifyOptions): string;
|
|
26
|
+
/**
|
|
27
|
+
* Check if a string is valid JSON
|
|
28
|
+
* @param input - String to validate
|
|
29
|
+
* @returns true if input is valid JSON, false otherwise
|
|
30
|
+
*/
|
|
31
|
+
export declare function isValidJSON(input: unknown): boolean;
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAcvD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAWpF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAenD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export { findValuesByKey as findJsonValues } from '../object/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Safely parse a JSON string
|
|
4
|
+
* @param input - JSON string to parse
|
|
5
|
+
* @returns Parsed JSON value
|
|
6
|
+
* @throws Error if input is not valid JSON
|
|
7
|
+
*/
|
|
8
|
+
export function parseJSON(input) {
|
|
9
|
+
if (typeof input !== 'string') {
|
|
10
|
+
throw new Error('Input must be a string');
|
|
11
|
+
}
|
|
12
|
+
if (input.trim() === '') {
|
|
13
|
+
throw new Error('Input cannot be empty');
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(input);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error(`Invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Safely stringify a value to JSON
|
|
24
|
+
* @param value - Value to stringify
|
|
25
|
+
* @param options - Stringification options
|
|
26
|
+
* @returns JSON string
|
|
27
|
+
* @throws Error if value contains circular references or cannot be stringified
|
|
28
|
+
*/
|
|
29
|
+
export function stringifyJSON(value, options = {}) {
|
|
30
|
+
const { pretty = false, indent = 2 } = options;
|
|
31
|
+
try {
|
|
32
|
+
if (pretty) {
|
|
33
|
+
return JSON.stringify(value, null, indent);
|
|
34
|
+
}
|
|
35
|
+
return JSON.stringify(value);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new Error(`Failed to stringify JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if a string is valid JSON
|
|
43
|
+
* @param input - String to validate
|
|
44
|
+
* @returns true if input is valid JSON, false otherwise
|
|
45
|
+
*/
|
|
46
|
+
export function isValidJSON(input) {
|
|
47
|
+
if (typeof input !== 'string') {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (input.trim() === '') {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
JSON.parse(input);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/json/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAYvE;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAc,KAAa;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,UAA4B,EAAE;IAC1E,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IAE/C,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic object query utilities for traversing parsed data structures.
|
|
3
|
+
*
|
|
4
|
+
* These functions work on any plain JS objects — parsed XML, JSON, or CSV rows
|
|
5
|
+
* are all objects by the time converters work with them.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Recursively find all values for a given key anywhere in a nested object tree.
|
|
9
|
+
*
|
|
10
|
+
* Walks the entire tree depth-first. When a property matching `key` is found,
|
|
11
|
+
* its value is collected. Recurse continues into all child values (objects and
|
|
12
|
+
* arrays) regardless of whether the current level matched.
|
|
13
|
+
*
|
|
14
|
+
* @param obj - Object tree to search (parsed XML, JSON, etc.)
|
|
15
|
+
* @param key - Property name to search for
|
|
16
|
+
* @param maxDepth - Maximum recursion depth (default 100). Nodes beyond this depth are silently skipped.
|
|
17
|
+
* @returns Flat array of all matched values
|
|
18
|
+
*/
|
|
19
|
+
export declare function findValuesByKey(obj: unknown, key: string, maxDepth?: number): unknown[];
|
|
20
|
+
/**
|
|
21
|
+
* Extract all values for a named field from an array of objects.
|
|
22
|
+
*
|
|
23
|
+
* Rows where the column is `undefined` are skipped.
|
|
24
|
+
*
|
|
25
|
+
* @param rows - Array of objects (e.g. parsed CSV rows)
|
|
26
|
+
* @param column - Property name to extract
|
|
27
|
+
* @returns Array of values for that column
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractColumn(rows: Record<string, unknown>[], column: string): unknown[];
|
|
30
|
+
/**
|
|
31
|
+
* Filter an array of objects to rows where a column matches a value.
|
|
32
|
+
*
|
|
33
|
+
* Uses strict equality (`===`).
|
|
34
|
+
*
|
|
35
|
+
* @param rows - Array of objects to filter
|
|
36
|
+
* @param column - Property name to check
|
|
37
|
+
* @param value - Value to match against
|
|
38
|
+
* @returns Filtered array of matching rows
|
|
39
|
+
*/
|
|
40
|
+
export declare function findRows(rows: Record<string, unknown>[], column: string, value: unknown): Record<string, unknown>[];
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|