node-pandas 1.0.4 → 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.
Files changed (41) hide show
  1. package/.kiro/agents/git-committer-agent.md +208 -0
  2. package/.kiro/agents/npm-publisher-agent.md +501 -0
  3. package/.kiro/publish-status-2.0.0.md +134 -0
  4. package/.kiro/published-versions.md +11 -0
  5. package/.kiro/specs/pandas-like-enhancements/.config.kiro +1 -0
  6. package/.kiro/specs/pandas-like-enhancements/design.md +377 -0
  7. package/.kiro/specs/pandas-like-enhancements/requirements.md +257 -0
  8. package/.kiro/specs/pandas-like-enhancements/tasks.md +477 -0
  9. package/CHANGELOG.md +42 -0
  10. package/README.md +375 -103
  11. package/TESTING_SETUP.md +183 -0
  12. package/jest.config.js +25 -0
  13. package/package.json +11 -3
  14. package/src/bases/CsvBase.js +4 -13
  15. package/src/dataframe/dataframe.js +596 -64
  16. package/src/features/GroupBy.js +561 -0
  17. package/src/features/dateRange.js +106 -0
  18. package/src/index.js +6 -1
  19. package/src/series/series.js +690 -14
  20. package/src/utils/errors.js +314 -0
  21. package/src/utils/getIndicesColumns.js +1 -1
  22. package/src/utils/getTransformedDataList.js +1 -1
  23. package/src/utils/logger.js +259 -0
  24. package/src/utils/typeDetection.js +339 -0
  25. package/src/utils/utils.js +5 -1
  26. package/src/utils/validation.js +450 -0
  27. package/tests/README.md +151 -0
  28. package/tests/integration/.gitkeep +0 -0
  29. package/tests/integration/README.md +3 -0
  30. package/tests/property/.gitkeep +0 -0
  31. package/tests/property/README.md +3 -0
  32. package/tests/setup.js +16 -0
  33. package/tests/test.js +58 -21
  34. package/tests/unit/.gitkeep +0 -0
  35. package/tests/unit/README.md +3 -0
  36. package/tests/unit/dataframe.test.js +1141 -0
  37. package/tests/unit/example.test.js +23 -0
  38. package/tests/unit/series.test.js +441 -0
  39. package/tests/unit/tocsv.test.js +838 -0
  40. package/tests/utils/testAssertions.js +143 -0
  41. package/tests/utils/testDataGenerator.js +123 -0
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Type Detection Utilities
3
+ *
4
+ * Provides comprehensive type detection and inference for data values,
5
+ * arrays, and DataFrame columns. Supports detection of numeric, string,
6
+ * boolean, date, and null types, with special handling for numeric strings.
7
+ *
8
+ * @module typeDetection
9
+ */
10
+
11
+ /**
12
+ * Detects if a value is null or undefined
13
+ *
14
+ * @param {*} value - The value to check
15
+ * @returns {boolean} True if value is null or undefined
16
+ *
17
+ * @example
18
+ * isNull(null) // true
19
+ * isNull(undefined) // true
20
+ * isNull(0) // false
21
+ * isNull('') // false
22
+ */
23
+ function isNull(value) {
24
+ return value === null || value === undefined;
25
+ }
26
+
27
+ /**
28
+ * Detects if a value is a boolean
29
+ *
30
+ * @param {*} value - The value to check
31
+ * @returns {boolean} True if value is a boolean
32
+ *
33
+ * @example
34
+ * isBoolean(true) // true
35
+ * isBoolean(false) // true
36
+ * isBoolean(1) // false
37
+ * isBoolean('true') // false
38
+ */
39
+ function isBoolean(value) {
40
+ return typeof value === 'boolean';
41
+ }
42
+
43
+ /**
44
+ * Detects if a value is a numeric string (can be parsed as a number)
45
+ *
46
+ * @param {*} value - The value to check
47
+ * @returns {boolean} True if value is a string that represents a number
48
+ *
49
+ * @example
50
+ * isNumericString('123') // true
51
+ * isNumericString('123.45') // true
52
+ * isNumericString('-456') // true
53
+ * isNumericString('abc') // false
54
+ * isNumericString('') // false
55
+ */
56
+ function isNumericString(value) {
57
+ if (typeof value !== 'string' || value.trim() === '') {
58
+ return false;
59
+ }
60
+ return !isNaN(parseFloat(value)) && isFinite(value);
61
+ }
62
+
63
+ /**
64
+ * Detects if a value is a number (including numeric strings)
65
+ *
66
+ * @param {*} value - The value to check
67
+ * @returns {boolean} True if value is a number or numeric string
68
+ *
69
+ * @example
70
+ * isNumeric(123) // true
71
+ * isNumeric(123.45) // true
72
+ * isNumeric('123') // true
73
+ * isNumeric('abc') // false
74
+ * isNumeric(null) // false
75
+ */
76
+ function isNumeric(value) {
77
+ if (isNull(value)) {
78
+ return false;
79
+ }
80
+ if (typeof value === 'number') {
81
+ return !isNaN(value) && isFinite(value);
82
+ }
83
+ return isNumericString(value);
84
+ }
85
+
86
+ /**
87
+ * Detects if a value is a string
88
+ *
89
+ * @param {*} value - The value to check
90
+ * @returns {boolean} True if value is a string
91
+ *
92
+ * @example
93
+ * isString('hello') // true
94
+ * isString('') // true
95
+ * isString(123) // false
96
+ * isString(null) // false
97
+ */
98
+ function isString(value) {
99
+ return typeof value === 'string';
100
+ }
101
+
102
+ /**
103
+ * Detects if a value is a Date object
104
+ *
105
+ * @param {*} value - The value to check
106
+ * @returns {boolean} True if value is a Date object
107
+ *
108
+ * @example
109
+ * isDate(new Date()) // true
110
+ * isDate('2023-01-01') // false
111
+ * isDate(1234567890) // false
112
+ */
113
+ function isDate(value) {
114
+ return value instanceof Date && !isNaN(value.getTime());
115
+ }
116
+
117
+ /**
118
+ * Detects if a value is a date string (ISO 8601 format)
119
+ *
120
+ * @param {*} value - The value to check
121
+ * @returns {boolean} True if value is a string in ISO 8601 date format
122
+ *
123
+ * @example
124
+ * isDateString('2023-01-01') // true
125
+ * isDateString('2023-01-01T12:00:00Z') // true
126
+ * isDateString('01/01/2023') // false
127
+ * isDateString('not a date') // false
128
+ */
129
+ function isDateString(value) {
130
+ if (!isString(value)) {
131
+ return false;
132
+ }
133
+ // ISO 8601 date format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss[.sss]Z
134
+ const isoDateRegex = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/;
135
+ if (!isoDateRegex.test(value)) {
136
+ return false;
137
+ }
138
+ const date = new Date(value);
139
+ return !isNaN(date.getTime());
140
+ }
141
+
142
+ /**
143
+ * Detects the type of a single value
144
+ *
145
+ * Returns one of: 'null', 'boolean', 'numeric', 'string', 'date', 'unknown'
146
+ *
147
+ * @param {*} value - The value to detect
148
+ * @returns {string} The detected type
149
+ *
150
+ * @example
151
+ * detectType(null) // 'null'
152
+ * detectType(true) // 'boolean'
153
+ * detectType(123) // 'numeric'
154
+ * detectType('hello') // 'string'
155
+ * detectType(new Date()) // 'date'
156
+ * detectType({}) // 'unknown'
157
+ */
158
+ function detectType(value) {
159
+ if (isNull(value)) {
160
+ return 'null';
161
+ }
162
+ if (isBoolean(value)) {
163
+ return 'boolean';
164
+ }
165
+ if (isDate(value)) {
166
+ return 'date';
167
+ }
168
+ if (isNumeric(value)) {
169
+ return 'numeric';
170
+ }
171
+ if (isString(value)) {
172
+ return 'string';
173
+ }
174
+ return 'unknown';
175
+ }
176
+
177
+ /**
178
+ * Infers the dominant type of an array of values
179
+ *
180
+ * Analyzes all values in the array and returns the most common type.
181
+ * Null values are ignored in type inference.
182
+ *
183
+ * @param {Array} array - The array to analyze
184
+ * @returns {string} The inferred type: 'null', 'boolean', 'numeric', 'string', 'date', or 'mixed'
185
+ *
186
+ * @example
187
+ * inferArrayType([1, 2, 3]) // 'numeric'
188
+ * inferArrayType(['a', 'b', 'c']) // 'string'
189
+ * inferArrayType([1, 'a', true]) // 'mixed'
190
+ * inferArrayType([null, null, null]) // 'null'
191
+ * inferArrayType([]) // 'null'
192
+ */
193
+ function inferArrayType(array) {
194
+ if (!Array.isArray(array) || array.length === 0) {
195
+ return 'null';
196
+ }
197
+
198
+ const typeCounts = {};
199
+ let nonNullCount = 0;
200
+
201
+ for (const value of array) {
202
+ const type = detectType(value);
203
+ if (type !== 'null') {
204
+ typeCounts[type] = (typeCounts[type] || 0) + 1;
205
+ nonNullCount++;
206
+ }
207
+ }
208
+
209
+ if (nonNullCount === 0) {
210
+ return 'null';
211
+ }
212
+
213
+ // If all non-null values are the same type, return that type
214
+ if (Object.keys(typeCounts).length === 1) {
215
+ return Object.keys(typeCounts)[0];
216
+ }
217
+
218
+ // If there are multiple types, return 'mixed'
219
+ return 'mixed';
220
+ }
221
+
222
+ /**
223
+ * Infers the type of a DataFrame column
224
+ *
225
+ * Analyzes all values in a column and returns the inferred type.
226
+ * This is a convenience wrapper around inferArrayType.
227
+ *
228
+ * @param {Array} column - The column data (array of values)
229
+ * @returns {string} The inferred type
230
+ *
231
+ * @example
232
+ * inferColumnType([1, 2, 3, null]) // 'numeric'
233
+ * inferColumnType(['a', 'b', null]) // 'string'
234
+ */
235
+ function inferColumnType(column) {
236
+ return inferArrayType(column);
237
+ }
238
+
239
+ /**
240
+ * Infers types for all columns in a DataFrame
241
+ *
242
+ * @param {Array<Array>} data - 2D array where each inner array is a column
243
+ * @param {Array<string>} [columnNames] - Optional column names for reference
244
+ * @returns {Object} Object mapping column names/indices to inferred types
245
+ *
246
+ * @example
247
+ * inferDataFrameTypes([[1, 2, 3], ['a', 'b', 'c']])
248
+ * // { '0': 'numeric', '1': 'string' }
249
+ *
250
+ * inferDataFrameTypes([[1, 2, 3], ['a', 'b', 'c']], ['id', 'name'])
251
+ * // { id: 'numeric', name: 'string' }
252
+ */
253
+ function inferDataFrameTypes(data, columnNames = null) {
254
+ const types = {};
255
+
256
+ if (!Array.isArray(data) || data.length === 0) {
257
+ return types;
258
+ }
259
+
260
+ // Handle row-based data (array of objects or arrays)
261
+ if (Array.isArray(data[0]) && !Array.isArray(data[0][0])) {
262
+ // Row-based format: [[row1], [row2], ...]
263
+ const numCols = data[0].length;
264
+ for (let colIndex = 0; colIndex < numCols; colIndex++) {
265
+ const column = data.map(row => row[colIndex]);
266
+ const colName = columnNames ? columnNames[colIndex] : String(colIndex);
267
+ types[colName] = inferColumnType(column);
268
+ }
269
+ } else if (Array.isArray(data[0])) {
270
+ // Column-based format: [[col1], [col2], ...]
271
+ for (let colIndex = 0; colIndex < data.length; colIndex++) {
272
+ const colName = columnNames ? columnNames[colIndex] : String(colIndex);
273
+ types[colName] = inferColumnType(data[colIndex]);
274
+ }
275
+ }
276
+
277
+ return types;
278
+ }
279
+
280
+ /**
281
+ * Converts a value to its numeric representation if possible
282
+ *
283
+ * @param {*} value - The value to convert
284
+ * @returns {number|null} The numeric value, or null if conversion fails
285
+ *
286
+ * @example
287
+ * toNumeric(123) // 123
288
+ * toNumeric('456') // 456
289
+ * toNumeric('123.45') // 123.45
290
+ * toNumeric('abc') // null
291
+ * toNumeric(null) // null
292
+ */
293
+ function toNumeric(value) {
294
+ if (isNull(value)) {
295
+ return null;
296
+ }
297
+ if (typeof value === 'number') {
298
+ return isNaN(value) ? null : value;
299
+ }
300
+ if (isNumericString(value)) {
301
+ return parseFloat(value);
302
+ }
303
+ return null;
304
+ }
305
+
306
+ /**
307
+ * Converts a value to its string representation
308
+ *
309
+ * @param {*} value - The value to convert
310
+ * @returns {string|null} The string value, or null if value is null/undefined
311
+ *
312
+ * @example
313
+ * toString(123) // '123'
314
+ * toString('hello') // 'hello'
315
+ * toString(true) // 'true'
316
+ * toString(null) // null
317
+ */
318
+ function toString(value) {
319
+ if (isNull(value)) {
320
+ return null;
321
+ }
322
+ return String(value);
323
+ }
324
+
325
+ module.exports = {
326
+ isNull,
327
+ isBoolean,
328
+ isNumericString,
329
+ isNumeric,
330
+ isString,
331
+ isDate,
332
+ isDateString,
333
+ detectType,
334
+ inferArrayType,
335
+ inferColumnType,
336
+ inferDataFrameTypes,
337
+ toNumeric,
338
+ toString
339
+ };
@@ -2,12 +2,16 @@ const dataType = require('./dataType') // require('dataType') => Error: Cannot f
2
2
  const getTransformedDataList = require('./getTransformedDataList')
3
3
  const getIndicesColumns = require('./getIndicesColumns')
4
4
  const excludingColumns = require("./excludingColumns")
5
+ const typeDetection = require('./typeDetection')
6
+ const validation = require('./validation')
5
7
  // const readCsv = require('./readCsv')
6
8
 
7
9
  module.exports = {
8
10
  dataType,
9
11
  getTransformedDataList,
10
12
  getIndicesColumns,
11
- excludingColumns
13
+ excludingColumns,
14
+ typeDetection,
15
+ validation
12
16
  // readCsv
13
17
  }