@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.
@@ -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"}
@@ -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