@fileverse-dev/formulajs 4.4.18 → 4.4.20-mod-1
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/lib/browser/formula.js +137 -41
- package/lib/browser/formula.min.js +2 -2
- package/lib/browser/formula.min.js.map +1 -1
- package/lib/cjs/index.cjs +158 -42
- package/lib/esm/index.mjs +158 -43
- package/package.json +1 -1
- package/types/cjs/index.d.cts +2 -1
- package/types/esm/index.d.mts +2 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -1270,75 +1270,79 @@ function ROWS(array) {
|
|
|
1270
1270
|
* @param {*} by_col Optional. A logical value indicating the desired sort direction; FALSE to sort by row (default), TRUE to sort by column
|
|
1271
1271
|
* @returns
|
|
1272
1272
|
*/
|
|
1273
|
-
function SORT(
|
|
1274
|
-
if (!
|
|
1275
|
-
if (
|
|
1273
|
+
function SORT(inputArray, sortIndex = 1, isAscending, sortByColumn = false) {
|
|
1274
|
+
if (!inputArray || !Array.isArray(inputArray)) return na;
|
|
1275
|
+
if (inputArray.length === 0) return 0;
|
|
1276
1276
|
|
|
1277
|
-
let
|
|
1278
|
-
if (!
|
|
1279
|
-
|
|
1277
|
+
let sortColumnIndex = parseNumber(sortIndex);
|
|
1278
|
+
if (!sortColumnIndex || sortColumnIndex < 1) return value;
|
|
1279
|
+
sortColumnIndex = sortColumnIndex - 1;
|
|
1280
1280
|
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1283
|
-
if (
|
|
1281
|
+
const sortDirection = isAscending?.toLowerCase() === 'false' ? -1 : 1;
|
|
1282
|
+
const parsedSortDirection = parseNumber(sortDirection);
|
|
1283
|
+
if (parsedSortDirection !== 1 && parsedSortDirection !== -1) return value;
|
|
1284
1284
|
|
|
1285
|
-
const byCol = parseBool(by_col);
|
|
1286
|
-
if (typeof byCol !== "boolean") return name;
|
|
1287
1285
|
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1286
|
+
const isSortByColumn = parseBool(sortByColumn);
|
|
1287
|
+
if (typeof isSortByColumn !== "boolean") return name;
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
const normalizedMatrix = fillMatrix(inputArray);
|
|
1291
|
+
const orientedMatrix = isSortByColumn
|
|
1292
|
+
? transpose(normalizedMatrix)
|
|
1293
|
+
: normalizedMatrix;
|
|
1291
1294
|
|
|
1292
|
-
if (!
|
|
1293
|
-
return value;
|
|
1295
|
+
if (!orientedMatrix.length || !orientedMatrix[0] || sortColumnIndex >= orientedMatrix[0].length) {
|
|
1296
|
+
return value;
|
|
1294
1297
|
}
|
|
1295
1298
|
|
|
1296
|
-
|
|
1297
|
-
const isBlank = (v) => v === "" || v === null || v === undefined;
|
|
1299
|
+
const isBlank = (value) => value === "" || value === null || value === undefined;
|
|
1298
1300
|
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
+
// Comparator for sorting values
|
|
1302
|
+
const compareValues = (a, b) => {
|
|
1301
1303
|
const aBlank = isBlank(a);
|
|
1302
1304
|
const bBlank = isBlank(b);
|
|
1303
1305
|
if (aBlank && bBlank) return 0;
|
|
1304
1306
|
if (aBlank) return 1;
|
|
1305
1307
|
if (bBlank) return -1;
|
|
1306
1308
|
|
|
1307
|
-
//
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
1310
|
-
const
|
|
1311
|
-
const
|
|
1309
|
+
// Numeric comparison if possible
|
|
1310
|
+
const parsedA = parseNumber(a);
|
|
1311
|
+
const parsedB = parseNumber(b);
|
|
1312
|
+
const isANumber = Number.isFinite(parsedA);
|
|
1313
|
+
const isBNumber = Number.isFinite(parsedB);
|
|
1312
1314
|
|
|
1313
|
-
if (
|
|
1314
|
-
if (
|
|
1315
|
-
if (
|
|
1315
|
+
if (isANumber && isBNumber) {
|
|
1316
|
+
if (parsedA < parsedB) return -1;
|
|
1317
|
+
if (parsedA > parsedB) return 1;
|
|
1316
1318
|
return 0;
|
|
1317
1319
|
}
|
|
1318
1320
|
|
|
1319
|
-
// Fallback: case-insensitive string
|
|
1320
|
-
const
|
|
1321
|
-
const
|
|
1322
|
-
if (
|
|
1323
|
-
if (
|
|
1321
|
+
// Fallback: case-insensitive string comparison
|
|
1322
|
+
const stringA = (parseString(a) ?? "").toString().toLowerCase();
|
|
1323
|
+
const stringB = (parseString(b) ?? "").toString().toLowerCase();
|
|
1324
|
+
if (stringA < stringB) return -1;
|
|
1325
|
+
if (stringA > stringB) return 1;
|
|
1324
1326
|
return 0;
|
|
1325
1327
|
};
|
|
1326
1328
|
|
|
1327
|
-
|
|
1328
|
-
const decorated = working.map((row, i) => ({ row, i }));
|
|
1329
|
+
const rowsWithOriginalIndex = orientedMatrix.map((row, rowIndex) => ({ row, rowIndex }));
|
|
1329
1330
|
|
|
1330
|
-
|
|
1331
|
-
const
|
|
1332
|
-
if (
|
|
1333
|
-
|
|
1334
|
-
return A.i - B.i;
|
|
1331
|
+
rowsWithOriginalIndex.sort((rowA, rowB) => {
|
|
1332
|
+
const baseComparison = compareValues(rowA.row[sortColumnIndex], rowB.row[sortColumnIndex]);
|
|
1333
|
+
if (baseComparison !== 0) return baseComparison * parsedSortDirection;
|
|
1334
|
+
return rowA.rowIndex - rowB.rowIndex;
|
|
1335
1335
|
});
|
|
1336
1336
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1337
|
+
// Extract sorted rows
|
|
1338
|
+
const sortedMatrix = rowsWithOriginalIndex.map((item) => item.row);
|
|
1339
|
+
|
|
1340
|
+
// Return rows or columns depending on orientation
|
|
1341
|
+
return isSortByColumn ? transpose(sortedMatrix) : sortedMatrix;
|
|
1339
1342
|
}
|
|
1340
1343
|
|
|
1341
1344
|
|
|
1345
|
+
|
|
1342
1346
|
/**
|
|
1343
1347
|
* Returns the transpose of an array.
|
|
1344
1348
|
*
|
|
@@ -1437,6 +1441,117 @@ function VLOOKUP(lookup_value, table_array, col_index_num, range_lookup) {
|
|
|
1437
1441
|
return result
|
|
1438
1442
|
}
|
|
1439
1443
|
|
|
1444
|
+
function XLOOKUP(lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode) {
|
|
1445
|
+
// Handle case where error object might not be defined
|
|
1446
|
+
const ERROR_NA = '#N/A';
|
|
1447
|
+
const ERROR_REF = '#REF!';
|
|
1448
|
+
|
|
1449
|
+
console.log('XLOOKUP parameters:', { lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode });
|
|
1450
|
+
|
|
1451
|
+
console.log('XLOOKUP called with:', { lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode });
|
|
1452
|
+
|
|
1453
|
+
// Handle VLOOKUP-style call: XLOOKUP("a", F7:G9, 2, "false")
|
|
1454
|
+
if (typeof return_array === 'number' && Array.isArray(lookup_array) && Array.isArray(lookup_array[0])) {
|
|
1455
|
+
console.log('Detected VLOOKUP-style call');
|
|
1456
|
+
const table_array = lookup_array;
|
|
1457
|
+
const col_index_num = return_array;
|
|
1458
|
+
const range_lookup = !(if_not_found === "false" || if_not_found === false || if_not_found === 0);
|
|
1459
|
+
|
|
1460
|
+
// Validate column index
|
|
1461
|
+
if (col_index_num < 1 || col_index_num > table_array[0].length) {
|
|
1462
|
+
return ERROR_REF
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Extract lookup and return columns
|
|
1466
|
+
const lookup_col = table_array.map(row => row[0]);
|
|
1467
|
+
const return_col = table_array.map(row => row[col_index_num - 1]);
|
|
1468
|
+
|
|
1469
|
+
return performLookup(lookup_value, lookup_col, return_col, ERROR_NA, range_lookup ? -1 : 0)
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// Standard XLOOKUP call: XLOOKUP("a", F7:F9, G7:G9, "hahaha")
|
|
1473
|
+
console.log('Detected standard XLOOKUP call');
|
|
1474
|
+
|
|
1475
|
+
if (!lookup_array || !return_array) {
|
|
1476
|
+
console.log('Missing lookup_array or return_array');
|
|
1477
|
+
return ERROR_NA
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// Handle case where arrays might be 2D (from Excel ranges)
|
|
1481
|
+
let lookup_col = lookup_array;
|
|
1482
|
+
let return_col = return_array;
|
|
1483
|
+
|
|
1484
|
+
// If lookup_array is 2D, extract first column
|
|
1485
|
+
if (Array.isArray(lookup_array) && Array.isArray(lookup_array[0])) {
|
|
1486
|
+
lookup_col = lookup_array.map(row => row[0]);
|
|
1487
|
+
console.log('Extracted lookup column from 2D array:', lookup_col);
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
// If return_array is 2D, extract first column
|
|
1491
|
+
if (Array.isArray(return_array) && Array.isArray(return_array[0])) {
|
|
1492
|
+
return_col = return_array.map(row => row[0]);
|
|
1493
|
+
console.log('Extracted return column from 2D array:', return_col);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
if (lookup_col.length !== return_col.length) {
|
|
1497
|
+
console.log('Array length mismatch:', lookup_col.length, 'vs', return_col.length);
|
|
1498
|
+
return ERROR_NA
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// Default parameters
|
|
1502
|
+
if_not_found = if_not_found !== undefined ? if_not_found : ERROR_NA;
|
|
1503
|
+
match_mode = match_mode || 0; // 0 = exact match, -1 = exact or next smallest
|
|
1504
|
+
search_mode = search_mode || 1; // 1 = first to last, -1 = last to first
|
|
1505
|
+
|
|
1506
|
+
return performLookup(lookup_value, lookup_col, return_col, if_not_found, match_mode, search_mode)
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
|
|
1510
|
+
function performLookup(lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode) {
|
|
1511
|
+
const isNumberLookup = typeof lookup_value === 'number';
|
|
1512
|
+
const lookupValue = typeof lookup_value === 'string' ? lookup_value.toLowerCase().trim() : lookup_value;
|
|
1513
|
+
let bestMatchIndex = -1;
|
|
1514
|
+
|
|
1515
|
+
// Debug: Log what we're looking for and what we have
|
|
1516
|
+
console.log('XLOOKUP Debug:', {
|
|
1517
|
+
looking_for: lookup_value,
|
|
1518
|
+
processed_lookup: lookupValue,
|
|
1519
|
+
lookup_array: lookup_array,
|
|
1520
|
+
return_array: return_array,
|
|
1521
|
+
match_mode: match_mode
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
// Determine search direction
|
|
1525
|
+
const startIndex = search_mode === -1 ? lookup_array.length - 1 : 0;
|
|
1526
|
+
const endIndex = search_mode === -1 ? -1 : lookup_array.length;
|
|
1527
|
+
const step = search_mode === -1 ? -1 : 1;
|
|
1528
|
+
|
|
1529
|
+
for (let i = startIndex; i !== endIndex; i += step) {
|
|
1530
|
+
const rawValue = lookup_array[i];
|
|
1531
|
+
const arrayValue = typeof rawValue === 'string' ? rawValue.toLowerCase().trim() : rawValue;
|
|
1532
|
+
|
|
1533
|
+
console.log(`Comparing: "${lookupValue}" === "${arrayValue}" (types: ${typeof lookupValue} vs ${typeof arrayValue})`);
|
|
1534
|
+
|
|
1535
|
+
// Exact match
|
|
1536
|
+
if (arrayValue === lookupValue) {
|
|
1537
|
+
console.log(`Found match at index ${i}: ${return_array[i]}`);
|
|
1538
|
+
return return_array[i]
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// Approximate match (match_mode = -1, similar to VLOOKUP range_lookup = true)
|
|
1542
|
+
if (match_mode === -1) {
|
|
1543
|
+
if ((isNumberLookup && typeof arrayValue === 'number' && arrayValue <= lookup_value) ||
|
|
1544
|
+
(!isNumberLookup && typeof arrayValue === 'string' && arrayValue.localeCompare(lookupValue) <= 0)) {
|
|
1545
|
+
bestMatchIndex = i;
|
|
1546
|
+
console.log(`Approximate match candidate at index ${i}: ${arrayValue}`);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
console.log(`No exact match found. Returning: ${bestMatchIndex !== -1 ? return_array[bestMatchIndex] : if_not_found}`);
|
|
1552
|
+
return bestMatchIndex !== -1 ? return_array[bestMatchIndex] : if_not_found
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1440
1555
|
/**
|
|
1441
1556
|
* Returns the character specified by the code number.
|
|
1442
1557
|
*
|
|
@@ -19236,6 +19351,7 @@ exports.WORKDAY = WORKDAY;
|
|
|
19236
19351
|
exports.WORKDAYINTL = WORKDAYINTL;
|
|
19237
19352
|
exports.WORKDAY_INTL = WORKDAY_INTL;
|
|
19238
19353
|
exports.XIRR = XIRR;
|
|
19354
|
+
exports.XLOOKUP = XLOOKUP;
|
|
19239
19355
|
exports.XNPV = XNPV;
|
|
19240
19356
|
exports.XOR = XOR;
|
|
19241
19357
|
exports.YEAR = YEAR;
|
package/lib/esm/index.mjs
CHANGED
|
@@ -1268,75 +1268,79 @@ function ROWS(array) {
|
|
|
1268
1268
|
* @param {*} by_col Optional. A logical value indicating the desired sort direction; FALSE to sort by row (default), TRUE to sort by column
|
|
1269
1269
|
* @returns
|
|
1270
1270
|
*/
|
|
1271
|
-
function SORT(
|
|
1272
|
-
if (!
|
|
1273
|
-
if (
|
|
1271
|
+
function SORT(inputArray, sortIndex = 1, isAscending, sortByColumn = false) {
|
|
1272
|
+
if (!inputArray || !Array.isArray(inputArray)) return na;
|
|
1273
|
+
if (inputArray.length === 0) return 0;
|
|
1274
1274
|
|
|
1275
|
-
let
|
|
1276
|
-
if (!
|
|
1277
|
-
|
|
1275
|
+
let sortColumnIndex = parseNumber(sortIndex);
|
|
1276
|
+
if (!sortColumnIndex || sortColumnIndex < 1) return value;
|
|
1277
|
+
sortColumnIndex = sortColumnIndex - 1;
|
|
1278
1278
|
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
if (
|
|
1279
|
+
const sortDirection = isAscending?.toLowerCase() === 'false' ? -1 : 1;
|
|
1280
|
+
const parsedSortDirection = parseNumber(sortDirection);
|
|
1281
|
+
if (parsedSortDirection !== 1 && parsedSortDirection !== -1) return value;
|
|
1282
1282
|
|
|
1283
|
-
const byCol = parseBool(by_col);
|
|
1284
|
-
if (typeof byCol !== "boolean") return name;
|
|
1285
1283
|
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1284
|
+
const isSortByColumn = parseBool(sortByColumn);
|
|
1285
|
+
if (typeof isSortByColumn !== "boolean") return name;
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
const normalizedMatrix = fillMatrix(inputArray);
|
|
1289
|
+
const orientedMatrix = isSortByColumn
|
|
1290
|
+
? transpose(normalizedMatrix)
|
|
1291
|
+
: normalizedMatrix;
|
|
1289
1292
|
|
|
1290
|
-
if (!
|
|
1291
|
-
return value;
|
|
1293
|
+
if (!orientedMatrix.length || !orientedMatrix[0] || sortColumnIndex >= orientedMatrix[0].length) {
|
|
1294
|
+
return value;
|
|
1292
1295
|
}
|
|
1293
1296
|
|
|
1294
|
-
|
|
1295
|
-
const isBlank = (v) => v === "" || v === null || v === undefined;
|
|
1297
|
+
const isBlank = (value) => value === "" || value === null || value === undefined;
|
|
1296
1298
|
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
+
// Comparator for sorting values
|
|
1300
|
+
const compareValues = (a, b) => {
|
|
1299
1301
|
const aBlank = isBlank(a);
|
|
1300
1302
|
const bBlank = isBlank(b);
|
|
1301
1303
|
if (aBlank && bBlank) return 0;
|
|
1302
1304
|
if (aBlank) return 1;
|
|
1303
1305
|
if (bBlank) return -1;
|
|
1304
1306
|
|
|
1305
|
-
//
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1308
|
-
const
|
|
1309
|
-
const
|
|
1307
|
+
// Numeric comparison if possible
|
|
1308
|
+
const parsedA = parseNumber(a);
|
|
1309
|
+
const parsedB = parseNumber(b);
|
|
1310
|
+
const isANumber = Number.isFinite(parsedA);
|
|
1311
|
+
const isBNumber = Number.isFinite(parsedB);
|
|
1310
1312
|
|
|
1311
|
-
if (
|
|
1312
|
-
if (
|
|
1313
|
-
if (
|
|
1313
|
+
if (isANumber && isBNumber) {
|
|
1314
|
+
if (parsedA < parsedB) return -1;
|
|
1315
|
+
if (parsedA > parsedB) return 1;
|
|
1314
1316
|
return 0;
|
|
1315
1317
|
}
|
|
1316
1318
|
|
|
1317
|
-
// Fallback: case-insensitive string
|
|
1318
|
-
const
|
|
1319
|
-
const
|
|
1320
|
-
if (
|
|
1321
|
-
if (
|
|
1319
|
+
// Fallback: case-insensitive string comparison
|
|
1320
|
+
const stringA = (parseString(a) ?? "").toString().toLowerCase();
|
|
1321
|
+
const stringB = (parseString(b) ?? "").toString().toLowerCase();
|
|
1322
|
+
if (stringA < stringB) return -1;
|
|
1323
|
+
if (stringA > stringB) return 1;
|
|
1322
1324
|
return 0;
|
|
1323
1325
|
};
|
|
1324
1326
|
|
|
1325
|
-
|
|
1326
|
-
const decorated = working.map((row, i) => ({ row, i }));
|
|
1327
|
+
const rowsWithOriginalIndex = orientedMatrix.map((row, rowIndex) => ({ row, rowIndex }));
|
|
1327
1328
|
|
|
1328
|
-
|
|
1329
|
-
const
|
|
1330
|
-
if (
|
|
1331
|
-
|
|
1332
|
-
return A.i - B.i;
|
|
1329
|
+
rowsWithOriginalIndex.sort((rowA, rowB) => {
|
|
1330
|
+
const baseComparison = compareValues(rowA.row[sortColumnIndex], rowB.row[sortColumnIndex]);
|
|
1331
|
+
if (baseComparison !== 0) return baseComparison * parsedSortDirection;
|
|
1332
|
+
return rowA.rowIndex - rowB.rowIndex;
|
|
1333
1333
|
});
|
|
1334
1334
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1335
|
+
// Extract sorted rows
|
|
1336
|
+
const sortedMatrix = rowsWithOriginalIndex.map((item) => item.row);
|
|
1337
|
+
|
|
1338
|
+
// Return rows or columns depending on orientation
|
|
1339
|
+
return isSortByColumn ? transpose(sortedMatrix) : sortedMatrix;
|
|
1337
1340
|
}
|
|
1338
1341
|
|
|
1339
1342
|
|
|
1343
|
+
|
|
1340
1344
|
/**
|
|
1341
1345
|
* Returns the transpose of an array.
|
|
1342
1346
|
*
|
|
@@ -1435,6 +1439,117 @@ function VLOOKUP(lookup_value, table_array, col_index_num, range_lookup) {
|
|
|
1435
1439
|
return result
|
|
1436
1440
|
}
|
|
1437
1441
|
|
|
1442
|
+
function XLOOKUP(lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode) {
|
|
1443
|
+
// Handle case where error object might not be defined
|
|
1444
|
+
const ERROR_NA = '#N/A';
|
|
1445
|
+
const ERROR_REF = '#REF!';
|
|
1446
|
+
|
|
1447
|
+
console.log('XLOOKUP parameters:', { lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode });
|
|
1448
|
+
|
|
1449
|
+
console.log('XLOOKUP called with:', { lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode });
|
|
1450
|
+
|
|
1451
|
+
// Handle VLOOKUP-style call: XLOOKUP("a", F7:G9, 2, "false")
|
|
1452
|
+
if (typeof return_array === 'number' && Array.isArray(lookup_array) && Array.isArray(lookup_array[0])) {
|
|
1453
|
+
console.log('Detected VLOOKUP-style call');
|
|
1454
|
+
const table_array = lookup_array;
|
|
1455
|
+
const col_index_num = return_array;
|
|
1456
|
+
const range_lookup = !(if_not_found === "false" || if_not_found === false || if_not_found === 0);
|
|
1457
|
+
|
|
1458
|
+
// Validate column index
|
|
1459
|
+
if (col_index_num < 1 || col_index_num > table_array[0].length) {
|
|
1460
|
+
return ERROR_REF
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// Extract lookup and return columns
|
|
1464
|
+
const lookup_col = table_array.map(row => row[0]);
|
|
1465
|
+
const return_col = table_array.map(row => row[col_index_num - 1]);
|
|
1466
|
+
|
|
1467
|
+
return performLookup(lookup_value, lookup_col, return_col, ERROR_NA, range_lookup ? -1 : 0)
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
// Standard XLOOKUP call: XLOOKUP("a", F7:F9, G7:G9, "hahaha")
|
|
1471
|
+
console.log('Detected standard XLOOKUP call');
|
|
1472
|
+
|
|
1473
|
+
if (!lookup_array || !return_array) {
|
|
1474
|
+
console.log('Missing lookup_array or return_array');
|
|
1475
|
+
return ERROR_NA
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// Handle case where arrays might be 2D (from Excel ranges)
|
|
1479
|
+
let lookup_col = lookup_array;
|
|
1480
|
+
let return_col = return_array;
|
|
1481
|
+
|
|
1482
|
+
// If lookup_array is 2D, extract first column
|
|
1483
|
+
if (Array.isArray(lookup_array) && Array.isArray(lookup_array[0])) {
|
|
1484
|
+
lookup_col = lookup_array.map(row => row[0]);
|
|
1485
|
+
console.log('Extracted lookup column from 2D array:', lookup_col);
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
// If return_array is 2D, extract first column
|
|
1489
|
+
if (Array.isArray(return_array) && Array.isArray(return_array[0])) {
|
|
1490
|
+
return_col = return_array.map(row => row[0]);
|
|
1491
|
+
console.log('Extracted return column from 2D array:', return_col);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
if (lookup_col.length !== return_col.length) {
|
|
1495
|
+
console.log('Array length mismatch:', lookup_col.length, 'vs', return_col.length);
|
|
1496
|
+
return ERROR_NA
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// Default parameters
|
|
1500
|
+
if_not_found = if_not_found !== undefined ? if_not_found : ERROR_NA;
|
|
1501
|
+
match_mode = match_mode || 0; // 0 = exact match, -1 = exact or next smallest
|
|
1502
|
+
search_mode = search_mode || 1; // 1 = first to last, -1 = last to first
|
|
1503
|
+
|
|
1504
|
+
return performLookup(lookup_value, lookup_col, return_col, if_not_found, match_mode, search_mode)
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
function performLookup(lookup_value, lookup_array, return_array, if_not_found, match_mode, search_mode) {
|
|
1509
|
+
const isNumberLookup = typeof lookup_value === 'number';
|
|
1510
|
+
const lookupValue = typeof lookup_value === 'string' ? lookup_value.toLowerCase().trim() : lookup_value;
|
|
1511
|
+
let bestMatchIndex = -1;
|
|
1512
|
+
|
|
1513
|
+
// Debug: Log what we're looking for and what we have
|
|
1514
|
+
console.log('XLOOKUP Debug:', {
|
|
1515
|
+
looking_for: lookup_value,
|
|
1516
|
+
processed_lookup: lookupValue,
|
|
1517
|
+
lookup_array: lookup_array,
|
|
1518
|
+
return_array: return_array,
|
|
1519
|
+
match_mode: match_mode
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
// Determine search direction
|
|
1523
|
+
const startIndex = search_mode === -1 ? lookup_array.length - 1 : 0;
|
|
1524
|
+
const endIndex = search_mode === -1 ? -1 : lookup_array.length;
|
|
1525
|
+
const step = search_mode === -1 ? -1 : 1;
|
|
1526
|
+
|
|
1527
|
+
for (let i = startIndex; i !== endIndex; i += step) {
|
|
1528
|
+
const rawValue = lookup_array[i];
|
|
1529
|
+
const arrayValue = typeof rawValue === 'string' ? rawValue.toLowerCase().trim() : rawValue;
|
|
1530
|
+
|
|
1531
|
+
console.log(`Comparing: "${lookupValue}" === "${arrayValue}" (types: ${typeof lookupValue} vs ${typeof arrayValue})`);
|
|
1532
|
+
|
|
1533
|
+
// Exact match
|
|
1534
|
+
if (arrayValue === lookupValue) {
|
|
1535
|
+
console.log(`Found match at index ${i}: ${return_array[i]}`);
|
|
1536
|
+
return return_array[i]
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// Approximate match (match_mode = -1, similar to VLOOKUP range_lookup = true)
|
|
1540
|
+
if (match_mode === -1) {
|
|
1541
|
+
if ((isNumberLookup && typeof arrayValue === 'number' && arrayValue <= lookup_value) ||
|
|
1542
|
+
(!isNumberLookup && typeof arrayValue === 'string' && arrayValue.localeCompare(lookupValue) <= 0)) {
|
|
1543
|
+
bestMatchIndex = i;
|
|
1544
|
+
console.log(`Approximate match candidate at index ${i}: ${arrayValue}`);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
console.log(`No exact match found. Returning: ${bestMatchIndex !== -1 ? return_array[bestMatchIndex] : if_not_found}`);
|
|
1550
|
+
return bestMatchIndex !== -1 ? return_array[bestMatchIndex] : if_not_found
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1438
1553
|
/**
|
|
1439
1554
|
* Returns the character specified by the code number.
|
|
1440
1555
|
*
|
|
@@ -18821,4 +18936,4 @@ function MYANIMELIST() {
|
|
|
18821
18936
|
|
|
18822
18937
|
const utils = { errors, symbols, date };
|
|
18823
18938
|
|
|
18824
|
-
export { AAVE, ABS, ACCRINT, ACOS, ACOSH, ACOT, ACOTH, AGGREGATE, AND, ARABIC, ARTEMIS, ASIN, ASINH, ATAN, ATAN2, ATANH, AVEDEV, AVERAGE, AVERAGEA, AVERAGEIF, AVERAGEIFS, BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BETA, BETADIST, BETAINV, BIN2DEC, BIN2HEX, BIN2OCT, BINOM, BINOMDIST, BITAND, BITLSHIFT, BITOR, BITRSHIFT, BITXOR, BLOCKSCOUT, CEILING, CEILINGMATH, CEILINGPRECISE, CHAR, CHIDIST, CHIDISTRT, CHIINV, CHIINVRT, CHISQ, CHITEST, CHOOSE, CLEAN, CODE, COINGECKO, COLUMN, COLUMNS, COMBIN, COMBINA, COMPLEX, CONCAT, CONCATENATE, CONFIDENCE, CONVERT, CORREL, COS, COSH, COT, COTH, COUNT, COUNTA, COUNTBLANK, COUNTIF, COUNTIFS, COUPDAYS, COVAR, COVARIANCE, COVARIANCEP, COVARIANCES, CRITBINOM, CSC, CSCH, CUMIPMT, CUMPRINC, DATE, DATEDIF, DATEVALUE, DAVERAGE, DAY, DAYS, DAYS360, DB, DCOUNT, DCOUNTA, DDB, DEC2BIN, DEC2HEX, DEC2OCT, DECIMAL, DEFILLAMA, DEGREES, DELTA, DEVSQ, DGET, DISC, DMAX, DMIN, DOLLAR, DOLLARDE, DOLLARFR, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DUNE, DVAR, DVARP, EDATE, EFFECT, EOA, EOMONTH, ERF, ERFC, ERFCPRECISE, ERFPRECISE, ERROR, ETHERSCAN, EVEN, EXACT, EXP, EXPON, EXPONDIST, F, FACT, FACTDOUBLE, FALSE, FARCASTER, FDIST, FDISTRT, FIND, FINV, FINVRT, FIREFLY, FISHER, FISHERINV, FIXED, FLOOR, FLOORMATH, FLOORPRECISE, FLVURL, FORECAST, FREQUENCY, FTEST, FV, FVSCHEDULE, GAMMA, GAMMADIST, GAMMAINV, GAMMALN, GAMMALNPRECISE, GAUSS, GCD, GEOMEAN, GESTEP, GNOSIS, GROWTH, HARMEAN, HEX2BIN, HEX2DEC, HEX2OCT, HLOOKUP, HOUR, HYPGEOM, HYPGEOMDIST, IF, IFERROR, IFNA, IFS, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMCOT, IMCSC, IMCSCH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSEC, IMSECH, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, INDEX, INT, INTERCEPT, IPMT, IRR, ISBLANK, ISDATE, ISERR, ISERROR, ISEVEN, ISLOGICAL, ISNA, ISNONTEXT, ISNUMBER, ISO, ISODD, ISOWEEKNUM, ISPMT, ISTEXT, KURT, LARGE, LCM, LEFT, LEN, LENS, LINEST, LN, LOG, LOG10, LOGEST, LOGINV, LOGNORM, LOGNORMDIST, LOGNORMINV, LOOKUP, LOWER, MATCH, MAX, MAXA, MAXIFS, MEDIAN, MEERKAT, MID, MIN, MINA, MINIFS, MINUS$1 as MINUS, MINUTE, MIRR, MMULT, MOD, MODE, MODEMULT, MODESNGL, MONTH, MROUND, MULTINOMIAL, MUNIT, MYANIMELIST, N, NA, NEGBINOM, NEGBINOMDIST, NETWORKDAYS, NETWORKDAYSINTL, NETWORKDAYS_INTL, NEYNAR, NOMINAL, NORM, NORMDIST, NORMINV, NORMSDIST, NORMSINV, NOT, NOW, NPER, NPV, NUMBERVALUE, OCT2BIN, OCT2DEC, OCT2HEX, ODD, OR, PDURATION, PEARSON, PERCENTILE, PERCENTILEEXC, PERCENTILEINC, PERCENTRANK, PERCENTRANKEXC, PERCENTRANKINC, PERMUT, PERMUTATIONA, PHI, PI, PMT, PNL, POISSON, POISSONDIST, POLYMARKET, POWER, PPMT, PRICEDISC, PRIVACYPOOL, PROB, PRODUCT, PROPER, PV, QUARTILE, QUARTILEEXC, QUARTILEINC, QUOTIENT, RADIANS, RAND, RANDBETWEEN, RANK, RANKAVG, RANKEQ, RATE, REPLACE, REPT, RIGHT, ROMAN, ROTKI, ROUND, ROUNDDOWN, ROUNDUP, ROW, ROWS, RRI, RSQ, SAFE, SEARCH, SEC, SECH, SECOND, SERIESSUM, SIGN, SIN, SINH, SKEW, SKEWP, SLN, SLOPE, SMALL, SMARTCONTRACT, SORT, SQRT, SQRTPI, STANDARDIZE, STDEV, STDEVA, STDEVP, STDEVPA, STDEVS, STEYX, SUBSTITUTE, SUBTOTAL, SUM, SUMIF, SUMIFS, SUMPRODUCT, SUMSQ, SUMX2MY2, SUMX2PY2, SUMXMY2, SWITCH, SYD, T, TALLY, TAN, TANH, TBILLEQ, TBILLPRICE, TBILLYIELD, TDIST, TDISTRT, TEXT, TEXTJOIN, TIME, TIMEVALUE, TINV, TODAY, TRANSPOSE, TREND, TRIM, TRIMMEAN, TRUE, TRUNC, TTEST, TYPE, UNICHAR, UNICODE, UNIQUE, UNISWAP, UPPER, VALUE, VAR, VARA, VARP, VARPA, VARS, VLOOKUP, WEEKDAY, WEEKNUM, WEIBULL, WEIBULLDIST, WORKDAY, WORKDAYINTL, WORKDAY_INTL, XIRR, XNPV, XOR, YEAR, YEARFRAC, Z, ZTEST, utils };
|
|
18939
|
+
export { AAVE, ABS, ACCRINT, ACOS, ACOSH, ACOT, ACOTH, AGGREGATE, AND, ARABIC, ARTEMIS, ASIN, ASINH, ATAN, ATAN2, ATANH, AVEDEV, AVERAGE, AVERAGEA, AVERAGEIF, AVERAGEIFS, BASE, BESSELI, BESSELJ, BESSELK, BESSELY, BETA, BETADIST, BETAINV, BIN2DEC, BIN2HEX, BIN2OCT, BINOM, BINOMDIST, BITAND, BITLSHIFT, BITOR, BITRSHIFT, BITXOR, BLOCKSCOUT, CEILING, CEILINGMATH, CEILINGPRECISE, CHAR, CHIDIST, CHIDISTRT, CHIINV, CHIINVRT, CHISQ, CHITEST, CHOOSE, CLEAN, CODE, COINGECKO, COLUMN, COLUMNS, COMBIN, COMBINA, COMPLEX, CONCAT, CONCATENATE, CONFIDENCE, CONVERT, CORREL, COS, COSH, COT, COTH, COUNT, COUNTA, COUNTBLANK, COUNTIF, COUNTIFS, COUPDAYS, COVAR, COVARIANCE, COVARIANCEP, COVARIANCES, CRITBINOM, CSC, CSCH, CUMIPMT, CUMPRINC, DATE, DATEDIF, DATEVALUE, DAVERAGE, DAY, DAYS, DAYS360, DB, DCOUNT, DCOUNTA, DDB, DEC2BIN, DEC2HEX, DEC2OCT, DECIMAL, DEFILLAMA, DEGREES, DELTA, DEVSQ, DGET, DISC, DMAX, DMIN, DOLLAR, DOLLARDE, DOLLARFR, DPRODUCT, DSTDEV, DSTDEVP, DSUM, DUNE, DVAR, DVARP, EDATE, EFFECT, EOA, EOMONTH, ERF, ERFC, ERFCPRECISE, ERFPRECISE, ERROR, ETHERSCAN, EVEN, EXACT, EXP, EXPON, EXPONDIST, F, FACT, FACTDOUBLE, FALSE, FARCASTER, FDIST, FDISTRT, FIND, FINV, FINVRT, FIREFLY, FISHER, FISHERINV, FIXED, FLOOR, FLOORMATH, FLOORPRECISE, FLVURL, FORECAST, FREQUENCY, FTEST, FV, FVSCHEDULE, GAMMA, GAMMADIST, GAMMAINV, GAMMALN, GAMMALNPRECISE, GAUSS, GCD, GEOMEAN, GESTEP, GNOSIS, GROWTH, HARMEAN, HEX2BIN, HEX2DEC, HEX2OCT, HLOOKUP, HOUR, HYPGEOM, HYPGEOMDIST, IF, IFERROR, IFNA, IFS, IMABS, IMAGINARY, IMARGUMENT, IMCONJUGATE, IMCOS, IMCOSH, IMCOT, IMCSC, IMCSCH, IMDIV, IMEXP, IMLN, IMLOG10, IMLOG2, IMPOWER, IMPRODUCT, IMREAL, IMSEC, IMSECH, IMSIN, IMSINH, IMSQRT, IMSUB, IMSUM, IMTAN, INDEX, INT, INTERCEPT, IPMT, IRR, ISBLANK, ISDATE, ISERR, ISERROR, ISEVEN, ISLOGICAL, ISNA, ISNONTEXT, ISNUMBER, ISO, ISODD, ISOWEEKNUM, ISPMT, ISTEXT, KURT, LARGE, LCM, LEFT, LEN, LENS, LINEST, LN, LOG, LOG10, LOGEST, LOGINV, LOGNORM, LOGNORMDIST, LOGNORMINV, LOOKUP, LOWER, MATCH, MAX, MAXA, MAXIFS, MEDIAN, MEERKAT, MID, MIN, MINA, MINIFS, MINUS$1 as MINUS, MINUTE, MIRR, MMULT, MOD, MODE, MODEMULT, MODESNGL, MONTH, MROUND, MULTINOMIAL, MUNIT, MYANIMELIST, N, NA, NEGBINOM, NEGBINOMDIST, NETWORKDAYS, NETWORKDAYSINTL, NETWORKDAYS_INTL, NEYNAR, NOMINAL, NORM, NORMDIST, NORMINV, NORMSDIST, NORMSINV, NOT, NOW, NPER, NPV, NUMBERVALUE, OCT2BIN, OCT2DEC, OCT2HEX, ODD, OR, PDURATION, PEARSON, PERCENTILE, PERCENTILEEXC, PERCENTILEINC, PERCENTRANK, PERCENTRANKEXC, PERCENTRANKINC, PERMUT, PERMUTATIONA, PHI, PI, PMT, PNL, POISSON, POISSONDIST, POLYMARKET, POWER, PPMT, PRICEDISC, PRIVACYPOOL, PROB, PRODUCT, PROPER, PV, QUARTILE, QUARTILEEXC, QUARTILEINC, QUOTIENT, RADIANS, RAND, RANDBETWEEN, RANK, RANKAVG, RANKEQ, RATE, REPLACE, REPT, RIGHT, ROMAN, ROTKI, ROUND, ROUNDDOWN, ROUNDUP, ROW, ROWS, RRI, RSQ, SAFE, SEARCH, SEC, SECH, SECOND, SERIESSUM, SIGN, SIN, SINH, SKEW, SKEWP, SLN, SLOPE, SMALL, SMARTCONTRACT, SORT, SQRT, SQRTPI, STANDARDIZE, STDEV, STDEVA, STDEVP, STDEVPA, STDEVS, STEYX, SUBSTITUTE, SUBTOTAL, SUM, SUMIF, SUMIFS, SUMPRODUCT, SUMSQ, SUMX2MY2, SUMX2PY2, SUMXMY2, SWITCH, SYD, T, TALLY, TAN, TANH, TBILLEQ, TBILLPRICE, TBILLYIELD, TDIST, TDISTRT, TEXT, TEXTJOIN, TIME, TIMEVALUE, TINV, TODAY, TRANSPOSE, TREND, TRIM, TRIMMEAN, TRUE, TRUNC, TTEST, TYPE, UNICHAR, UNICODE, UNIQUE, UNISWAP, UPPER, VALUE, VAR, VARA, VARP, VARPA, VARS, VLOOKUP, WEEKDAY, WEEKNUM, WEIBULL, WEIBULLDIST, WORKDAY, WORKDAYINTL, WORKDAY_INTL, XIRR, XLOOKUP, XNPV, XOR, YEAR, YEARFRAC, Z, ZTEST, utils };
|
package/package.json
CHANGED
package/types/cjs/index.d.cts
CHANGED
|
@@ -3806,7 +3806,7 @@ export function SMARTCONTRACT(...args: any[]): Promise<any>;
|
|
|
3806
3806
|
* @param {*} by_col Optional. A logical value indicating the desired sort direction; FALSE to sort by row (default), TRUE to sort by column
|
|
3807
3807
|
* @returns
|
|
3808
3808
|
*/
|
|
3809
|
-
export function SORT(
|
|
3809
|
+
export function SORT(inputArray: any, sortIndex: number, isAscending: any, sortByColumn?: boolean): any;
|
|
3810
3810
|
/**
|
|
3811
3811
|
* Returns a positive square root.
|
|
3812
3812
|
*
|
|
@@ -4522,6 +4522,7 @@ export function WORKDAY_INTL(start_date: any, days: any, weekend: any, holidays:
|
|
|
4522
4522
|
* @returns
|
|
4523
4523
|
*/
|
|
4524
4524
|
export function XIRR(values: any, dates: any, guess: any): any;
|
|
4525
|
+
export function XLOOKUP(lookup_value: any, lookup_array: any, return_array: any, if_not_found: any, match_mode: any, search_mode: any): any;
|
|
4525
4526
|
/**
|
|
4526
4527
|
* Returns the net present value for a schedule of cash flows that is not necessarily periodic.
|
|
4527
4528
|
*
|
package/types/esm/index.d.mts
CHANGED
|
@@ -3806,7 +3806,7 @@ export function SMARTCONTRACT(...args: any[]): Promise<any>;
|
|
|
3806
3806
|
* @param {*} by_col Optional. A logical value indicating the desired sort direction; FALSE to sort by row (default), TRUE to sort by column
|
|
3807
3807
|
* @returns
|
|
3808
3808
|
*/
|
|
3809
|
-
export function SORT(
|
|
3809
|
+
export function SORT(inputArray: any, sortIndex: number, isAscending: any, sortByColumn?: boolean): any;
|
|
3810
3810
|
/**
|
|
3811
3811
|
* Returns a positive square root.
|
|
3812
3812
|
*
|
|
@@ -4522,6 +4522,7 @@ export function WORKDAY_INTL(start_date: any, days: any, weekend: any, holidays:
|
|
|
4522
4522
|
* @returns
|
|
4523
4523
|
*/
|
|
4524
4524
|
export function XIRR(values: any, dates: any, guess: any): any;
|
|
4525
|
+
export function XLOOKUP(lookup_value: any, lookup_array: any, return_array: any, if_not_found: any, match_mode: any, search_mode: any): any;
|
|
4525
4526
|
/**
|
|
4526
4527
|
* Returns the net present value for a schedule of cash flows that is not necessarily periodic.
|
|
4527
4528
|
*
|