sfdx-hardis 6.16.1-beta202512161830.0 → 6.17.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.
Files changed (38) hide show
  1. package/README.md +18 -6
  2. package/lib/commands/hardis/datacloud/extract/agentforce-conversations.d.ts +14 -0
  3. package/lib/commands/hardis/datacloud/extract/agentforce-conversations.js +369 -0
  4. package/lib/commands/hardis/datacloud/extract/agentforce-conversations.js.map +1 -0
  5. package/lib/commands/hardis/datacloud/extract/agentforce-feedback.d.ts +14 -0
  6. package/lib/commands/hardis/datacloud/extract/agentforce-feedback.js +333 -0
  7. package/lib/commands/hardis/datacloud/extract/agentforce-feedback.js.map +1 -0
  8. package/lib/commands/hardis/datacloud/sql-query.d.ts +14 -0
  9. package/lib/commands/hardis/datacloud/sql-query.js +145 -0
  10. package/lib/commands/hardis/datacloud/sql-query.js.map +1 -0
  11. package/lib/commands/hardis/org/select.js +1 -1
  12. package/lib/commands/hardis/org/select.js.map +1 -1
  13. package/lib/common/notifProvider/emailProvider.js +6 -1
  14. package/lib/common/notifProvider/emailProvider.js.map +1 -1
  15. package/lib/common/notifProvider/index.d.ts +2 -1
  16. package/lib/common/notifProvider/index.js +2 -2
  17. package/lib/common/notifProvider/index.js.map +1 -1
  18. package/lib/common/notifProvider/notifProviderRoot.js +3 -0
  19. package/lib/common/notifProvider/notifProviderRoot.js.map +1 -1
  20. package/lib/common/utils/agentforceQueryUtils.d.ts +48 -0
  21. package/lib/common/utils/agentforceQueryUtils.js +373 -0
  22. package/lib/common/utils/agentforceQueryUtils.js.map +1 -0
  23. package/lib/common/utils/authUtils.js +16 -3
  24. package/lib/common/utils/authUtils.js.map +1 -1
  25. package/lib/common/utils/dataCloudUtils.d.ts +39 -0
  26. package/lib/common/utils/dataCloudUtils.js +279 -0
  27. package/lib/common/utils/dataCloudUtils.js.map +1 -0
  28. package/lib/common/utils/filesUtils.d.ts +12 -13
  29. package/lib/common/utils/filesUtils.js +114 -43
  30. package/lib/common/utils/filesUtils.js.map +1 -1
  31. package/lib/common/utils/orgUtils.js +5 -1
  32. package/lib/common/utils/orgUtils.js.map +1 -1
  33. package/lib/common/utils/utilsAgentforceQuery.d.ts +1 -0
  34. package/lib/common/utils/utilsAgentforceQuery.js +2 -0
  35. package/lib/common/utils/utilsAgentforceQuery.js.map +1 -0
  36. package/oclif.lock +697 -697
  37. package/oclif.manifest.json +1405 -1020
  38. package/package.json +5 -5
@@ -0,0 +1,279 @@
1
+ import { SfError } from "@salesforce/core";
2
+ import { uxLog } from "./index.js";
3
+ import fs from "fs-extra";
4
+ import path from "path";
5
+ export const DATA_CLOUD_QUERIES_FOLDER_ROOT = path.join(process.cwd(), 'scripts', 'data-cloud-queries');
6
+ const QUERY_CONNECT_PATH = "ssot/query-sql";
7
+ const DEFAULT_DATASPACE = "default";
8
+ const DEFAULT_WORKLOAD_NAME = "sfdx-hardis-cli";
9
+ const DEFAULT_ROW_LIMIT = 2000;
10
+ const DEFAULT_POLL_INTERVAL_MS = 5000;
11
+ const DEFAULT_POLL_TIMEOUT_MS = 120000;
12
+ const DEFAULT_OMIT_SCHEMA = false;
13
+ const SUCCESS_STATUSES = new Set(["finished", "resultsproduced"]);
14
+ const RUNNING_STATUSES = new Set(["running", "queued"]);
15
+ const FAILURE_STATUSES = new Set(["failed", "canceled", "cancelled", "error"]);
16
+ export async function listAvailableDataCloudQueries() {
17
+ // List folders in DATA_CLOUD_QUERIES_FOLDER_ROOT
18
+ const queries = [];
19
+ if (fs.existsSync(DATA_CLOUD_QUERIES_FOLDER_ROOT)) {
20
+ const files = await fs.readdir(DATA_CLOUD_QUERIES_FOLDER_ROOT);
21
+ for (const file of files) {
22
+ const fullPath = path.join(DATA_CLOUD_QUERIES_FOLDER_ROOT, file);
23
+ const stat = await fs.stat(fullPath);
24
+ if (stat.isFile() && path.extname(file).toLowerCase() === '.sql') {
25
+ queries.push(path.basename(file, '.sql'));
26
+ }
27
+ }
28
+ }
29
+ return queries;
30
+ }
31
+ export async function loadDataCloudQueryFromFile(queryName) {
32
+ const filePath = path.join(DATA_CLOUD_QUERIES_FOLDER_ROOT, `${queryName}.sql`);
33
+ if (!fs.existsSync(filePath)) {
34
+ throw new SfError(`Data Cloud query file not found: ${filePath}`);
35
+ }
36
+ const queryContent = await fs.readFile(filePath, 'utf8');
37
+ return queryContent;
38
+ }
39
+ export async function saveDataCloudQueryToFile(queryName, queryContent) {
40
+ // Ensure the folder exists
41
+ await fs.ensureDir(DATA_CLOUD_QUERIES_FOLDER_ROOT);
42
+ const filePath = path.join(DATA_CLOUD_QUERIES_FOLDER_ROOT, `${queryName}.sql`);
43
+ await fs.writeFile(filePath, queryContent, 'utf8');
44
+ return filePath;
45
+ }
46
+ export async function dataCloudSqlQuery(query, conn, options) {
47
+ if (!query || !query.trim()) {
48
+ throw new SfError("[DataCloudSqlQuery] The Data Cloud SQL query must be a non-empty string.");
49
+ }
50
+ const settings = resolveOptions(options);
51
+ try {
52
+ const initialChunk = await submitInitialQuery(query.trim(), conn, settings);
53
+ if (!initialChunk.metadata.length) {
54
+ throw new SfError(`[DataCloudSqlQuery] Data Cloud SQL query did not return column metadata.\n${JSON.stringify(initialChunk)}`);
55
+ }
56
+ if (!initialChunk.status.queryId) {
57
+ throw new SfError(`[DataCloudSqlQuery] Data Cloud SQL query did not return a queryId needed for pagination.\n${JSON.stringify(initialChunk)}`);
58
+ }
59
+ let metadata = initialChunk.metadata;
60
+ const records = [...initialChunk.records];
61
+ const rawData = [...initialChunk.rawData];
62
+ let status = initialChunk.status;
63
+ status = await waitForQueryCompletion(conn, status, settings);
64
+ const pagination = await fetchRemainingRows(conn, status.queryId, metadata, records.length, status.rowCount, settings);
65
+ if (!metadata.length && pagination.metadata.length) {
66
+ metadata = pagination.metadata;
67
+ }
68
+ if (pagination.records.length) {
69
+ records.push(...pagination.records);
70
+ rawData.push(...pagination.rawData);
71
+ }
72
+ uxLog("log", this, `[DataCloudSqlQuery] Retrieved ${records.length} records.`);
73
+ return {
74
+ queryId: status.queryId,
75
+ metadata,
76
+ status: {
77
+ ...status,
78
+ rowCount: status.rowCount ?? records.length,
79
+ },
80
+ records,
81
+ rawData,
82
+ returnedRows: records.length,
83
+ hasMoreRows: false,
84
+ };
85
+ }
86
+ catch (error) {
87
+ throw wrapQueryError(error);
88
+ }
89
+ }
90
+ async function submitInitialQuery(query, conn, options) {
91
+ const endpoint = buildQueryConnectUrl(conn, options);
92
+ uxLog("log", this, `[DataCloudSqlQuery] Submitting initial query to ${endpoint}:\n${query}`);
93
+ const response = await conn.request({
94
+ method: "POST",
95
+ url: endpoint,
96
+ headers: { "content-type": "application/json" },
97
+ body: JSON.stringify({ sql: query }),
98
+ });
99
+ return normalizeQueryResponse(response);
100
+ }
101
+ async function waitForQueryCompletion(conn, status, options) {
102
+ const deadline = Date.now() + options.pollTimeoutMs;
103
+ let currentStatus = status;
104
+ while (isRunningStatus(currentStatus.completionStatus)) {
105
+ if (Date.now() > deadline) {
106
+ throw new SfError(`Timed out after ${options.pollTimeoutMs}ms while waiting for Data Cloud query ${currentStatus.queryId} to finish.`);
107
+ }
108
+ const waitTimeMs = Math.min(options.waitTimeMs, Math.max(0, deadline - Date.now()));
109
+ currentStatus = await fetchQueryStatus(conn, currentStatus.queryId, options, waitTimeMs);
110
+ if (isFailureStatus(currentStatus.completionStatus)) {
111
+ throw new SfError(`Data Cloud SQL query ${currentStatus.queryId} failed with status ${currentStatus.completionStatus}.`);
112
+ }
113
+ if (isRunningStatus(currentStatus.completionStatus) && options.pollIntervalMs > 0) {
114
+ await delay(options.pollIntervalMs);
115
+ }
116
+ }
117
+ if (!isSuccessStatus(currentStatus.completionStatus)) {
118
+ throw new SfError(`Unexpected Data Cloud SQL query status: ${currentStatus.completionStatus || "Unknown"}.`);
119
+ }
120
+ return currentStatus;
121
+ }
122
+ async function fetchRemainingRows(conn, queryId, metadata, alreadyFetched, totalRows, options) {
123
+ const rowLimit = Math.max(1, options.rowLimit);
124
+ const records = [];
125
+ const rawData = [];
126
+ let offset = alreadyFetched;
127
+ let remaining = typeof totalRows === "number" ? Math.max(totalRows - alreadyFetched, 0) : undefined;
128
+ while (remaining === undefined || remaining > 0) {
129
+ const response = await fetchRowsPage(conn, queryId, options, offset, rowLimit);
130
+ const rows = response.data ?? [];
131
+ if (response.metadata && !metadata.length) {
132
+ metadata = response.metadata;
133
+ }
134
+ if (!rows.length) {
135
+ break;
136
+ }
137
+ rawData.push(...rows);
138
+ records.push(...rows.map((row) => mapRowToRecord(row, metadata)));
139
+ offset += rows.length;
140
+ if (remaining !== undefined) {
141
+ remaining -= rows.length;
142
+ }
143
+ if (rows.length < rowLimit) {
144
+ break;
145
+ }
146
+ }
147
+ return { records, rawData, metadata };
148
+ }
149
+ async function fetchQueryStatus(conn, queryId, options, waitTimeMs) {
150
+ const url = buildQueryConnectUrl(conn, options, [queryId], {
151
+ waitTimeMs: waitTimeMs > 0 ? waitTimeMs : undefined,
152
+ });
153
+ const response = await conn.request({
154
+ method: "GET",
155
+ url,
156
+ });
157
+ return normalizeStatusResponse(response, queryId);
158
+ }
159
+ async function fetchRowsPage(conn, queryId, options, offset, rowLimit) {
160
+ const url = buildQueryConnectUrl(conn, options, [queryId, "rows"], {
161
+ rowLimit,
162
+ offset,
163
+ omitSchema: options.omitSchema,
164
+ });
165
+ return conn.request({
166
+ method: "GET",
167
+ url,
168
+ });
169
+ }
170
+ function normalizeQueryResponse(response) {
171
+ if (typeof response !== "object" || response === null) {
172
+ throw new SfError("Invalid response format received from Data Cloud SQL query.\n" + JSON.stringify(response, null, 2));
173
+ }
174
+ const metadata = response.metadata ?? [];
175
+ const dataRows = response.data ?? [];
176
+ const records = metadata.length ? dataRows.map((row) => mapRowToRecord(row, metadata)) : [];
177
+ const status = normalizeStatusResponse(response.status ?? {}, "");
178
+ return {
179
+ queryId: status.queryId,
180
+ metadata,
181
+ status,
182
+ records,
183
+ rawData: dataRows,
184
+ returnedRows: response.returnedRows ?? records.length,
185
+ hasMoreRows: hasMoreRowsPending(status, records.length),
186
+ };
187
+ }
188
+ function normalizeStatusResponse(status, fallbackQueryId) {
189
+ return {
190
+ chunkCount: status.chunkCount ?? 0,
191
+ completionStatus: status.completionStatus ?? "Unknown",
192
+ queryId: status.queryId ?? fallbackQueryId,
193
+ rowCount: status.rowCount,
194
+ expirationTime: status.expirationTime,
195
+ progress: status.progress,
196
+ };
197
+ }
198
+ function mapRowToRecord(row, metadata) {
199
+ if (!metadata.length) {
200
+ throw new SfError("Cannot map Data Cloud rows without column metadata.");
201
+ }
202
+ return metadata.reduce((acc, column, index) => {
203
+ acc[column.name] = row[index] ?? null;
204
+ return acc;
205
+ }, {});
206
+ }
207
+ function hasMoreRowsPending(status, fetchedRows) {
208
+ if (typeof status.rowCount === "number") {
209
+ return status.rowCount > fetchedRows;
210
+ }
211
+ const state = status.completionStatus?.toLowerCase();
212
+ return state === "running" || state === "resultsproduced";
213
+ }
214
+ function buildQueryConnectUrl(conn, options, pathSegments = [], queryParams = {}) {
215
+ const base = conn.baseUrl().replace(/\/$/, "");
216
+ const baseSegments = QUERY_CONNECT_PATH.split("/");
217
+ const path = [...baseSegments, ...pathSegments]
218
+ .filter((segment) => segment && segment.length)
219
+ .map((segment) => encodeURIComponent(segment))
220
+ .join("/");
221
+ const params = {
222
+ dataspace: options.dataspace,
223
+ workloadName: options.workloadName,
224
+ ...queryParams,
225
+ };
226
+ const queryString = Object.entries(params)
227
+ .filter(([, value]) => value !== undefined && value !== null && value !== "")
228
+ .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
229
+ .join("&");
230
+ return queryString ? `${base}/${path}?${queryString}` : `${base}/${path}`;
231
+ }
232
+ function resolveOptions(options) {
233
+ return {
234
+ dataspace: options?.dataspace || DEFAULT_DATASPACE,
235
+ workloadName: options?.workloadName || DEFAULT_WORKLOAD_NAME,
236
+ rowLimit: options?.rowLimit || DEFAULT_ROW_LIMIT,
237
+ pollIntervalMs: options?.pollIntervalMs || DEFAULT_POLL_INTERVAL_MS,
238
+ pollTimeoutMs: options?.pollTimeoutMs || DEFAULT_POLL_TIMEOUT_MS,
239
+ waitTimeMs: options?.waitTimeMs || DEFAULT_POLL_INTERVAL_MS,
240
+ omitSchema: options?.omitSchema ?? DEFAULT_OMIT_SCHEMA,
241
+ };
242
+ }
243
+ function isRunningStatus(status) {
244
+ return RUNNING_STATUSES.has(status?.toLowerCase());
245
+ }
246
+ function isSuccessStatus(status) {
247
+ return SUCCESS_STATUSES.has(status?.toLowerCase());
248
+ }
249
+ function isFailureStatus(status) {
250
+ return FAILURE_STATUSES.has(status?.toLowerCase());
251
+ }
252
+ function delay(ms) {
253
+ if (ms <= 0) {
254
+ return Promise.resolve();
255
+ }
256
+ return new Promise((resolve) => setTimeout(resolve, ms));
257
+ }
258
+ function wrapQueryError(error) {
259
+ if (isSfRequestError(error)) {
260
+ const details = [error.message];
261
+ const bodyMessage = error.body?.message;
262
+ const bodyDescription = error.body?.error_description;
263
+ if (bodyMessage) {
264
+ details.push(bodyMessage);
265
+ }
266
+ if (bodyDescription && bodyDescription !== bodyMessage) {
267
+ details.push(bodyDescription);
268
+ }
269
+ if (error.statusCode) {
270
+ details.push(`(status ${error.statusCode})`);
271
+ }
272
+ return new SfError(`[DataCloudSqlQuery] Data Cloud SQL query failed: ${details.filter(Boolean).join(" ")}`.trim());
273
+ }
274
+ return error instanceof SfError ? error : new SfError("[DataCloudSqlQuery] Unknown error while executing Data Cloud SQL query.");
275
+ }
276
+ function isSfRequestError(error) {
277
+ return Boolean(error && typeof error === "object" && "message" in error);
278
+ }
279
+ //# sourceMappingURL=dataCloudUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dataCloudUtils.js","sourceRoot":"","sources":["../../../src/common/utils/dataCloudUtils.ts"],"names":[],"mappings":"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"}
@@ -173,20 +173,19 @@ export declare function generateReportPath(fileNamePrefix: string, outputFile: s
173
173
  * @param {string} outputPath - The path where the CSV file will be written.
174
174
  * @returns {Promise<void>} - A Promise that resolves when the operation is complete.
175
175
  */
176
- export declare function generateCsvFile(data: any[], outputPath: string, options: {
177
- fileTitle?: string;
178
- csvFileTitle?: string;
179
- xlsFileTitle?: string;
180
- noExcel?: boolean;
181
- }): Promise<any>;
182
- export declare function createXlsxFromCsv(outputPath: string, options: {
176
+ export interface ExcelColumnStyle {
177
+ wrap?: boolean;
178
+ width?: number;
179
+ hyperlinkFromValue?: boolean;
180
+ maxHeight?: number;
181
+ }
182
+ export interface ExcelExportOptions {
183
183
  fileTitle?: string;
184
184
  csvFileTitle?: string;
185
185
  xlsFileTitle?: string;
186
186
  noExcel?: boolean;
187
- }, result: any): Promise<void>;
188
- export declare function createXlsxFromCsvFiles(csvFilesPath: string[], outputPath: string, options: {
189
- fileTitle?: string;
190
- csvFileTitle?: string;
191
- xlsFileTitle?: string;
192
- }): Promise<void>;
187
+ columnsCustomStyles?: Record<string, ExcelColumnStyle>;
188
+ }
189
+ export declare function generateCsvFile(data: any[], outputPath: string, options?: ExcelExportOptions): Promise<any>;
190
+ export declare function createXlsxFromCsv(outputPath: string, options: ExcelExportOptions, result: any): Promise<void>;
191
+ export declare function createXlsxFromCsvFiles(csvFilesPath: string[], outputPath: string, options?: ExcelExportOptions): Promise<void>;
@@ -1220,16 +1220,7 @@ export async function generateReportPath(fileNamePrefix, outputFile, options = {
1220
1220
  return outputFile;
1221
1221
  }
1222
1222
  }
1223
- /**
1224
- * @description This function generates a CSV file from the provided data and writes it to the specified output path.
1225
- * If the operation is successful, it logs a message and requests to open the file.
1226
- * If an error occurs during the operation, it logs the error message and stack trace.
1227
- *
1228
- * @param {any[]} data - The data to be written to the CSV file.
1229
- * @param {string} outputPath - The path where the CSV file will be written.
1230
- * @returns {Promise<void>} - A Promise that resolves when the operation is complete.
1231
- */
1232
- export async function generateCsvFile(data, outputPath, options) {
1223
+ export async function generateCsvFile(data, outputPath, options = {}) {
1233
1224
  const result = {};
1234
1225
  try {
1235
1226
  const csvContent = Papa.unparse(data);
@@ -1259,7 +1250,7 @@ export async function createXlsxFromCsv(outputPath, options, result) {
1259
1250
  const xslFileName = path.basename(outputPath).replace('.csv', '.xlsx');
1260
1251
  const xslxFile = path.join(xlsDirName, xslFileName);
1261
1252
  await fs.ensureDir(xlsDirName);
1262
- await csvToXls(outputPath, xslxFile);
1253
+ await csvToXls(outputPath, xslxFile, options);
1263
1254
  uxLog("action", this, c.cyan(c.italic(`Please see detailed XLSX log in ${c.bold(xslxFile)}`)));
1264
1255
  const xlsFileTitle = options?.fileTitle ? `${options.fileTitle} (XLSX)` : options?.xlsFileTitle ?? "Report (XLSX)";
1265
1256
  WebSocketClient.sendReportFileMessage(xslxFile, xlsFileTitle, "report");
@@ -1278,28 +1269,19 @@ export async function createXlsxFromCsv(outputPath, options, result) {
1278
1269
  uxLog("warning", this, c.yellow('Error while generating XLSX log file:\n' + e2.message + '\n' + e2.stack));
1279
1270
  }
1280
1271
  }
1281
- async function csvToXls(csvFile, xslxFile) {
1272
+ async function csvToXls(csvFile, xslxFile, options) {
1282
1273
  const workbook = new ExcelJS.Workbook();
1283
1274
  const worksheet = await workbook.csv.readFile(csvFile);
1284
- // Set filters
1285
- worksheet.autoFilter = 'A1:Z1';
1286
- // Adjust column size (only if the file is not too big, to avoid performances issues)
1287
- if (worksheet.rowCount < 5000) {
1288
- worksheet.columns.forEach((column) => {
1289
- const lengths = (column.values || []).map((v) => (v || '').toString().length);
1290
- const maxLength = Math.max(...lengths.filter((v) => typeof v === 'number'));
1291
- column.width = maxLength;
1292
- });
1293
- }
1275
+ applyWorksheetFormatting(worksheet, options);
1294
1276
  await workbook.xlsx.writeFile(xslxFile);
1295
1277
  }
1296
- export async function createXlsxFromCsvFiles(csvFilesPath, outputPath, options) {
1278
+ export async function createXlsxFromCsvFiles(csvFilesPath, outputPath, options = {}) {
1297
1279
  try {
1298
1280
  const xlsDirName = path.join(path.dirname(outputPath), 'xls');
1299
1281
  const xslFileName = path.basename(outputPath).replace('.csv', '.xlsx');
1300
1282
  const xslxFile = path.join(xlsDirName, xslFileName);
1301
1283
  await fs.ensureDir(xlsDirName);
1302
- await csvFilesToXls(csvFilesPath, xslxFile);
1284
+ await csvFilesToXls(csvFilesPath, xslxFile, options);
1303
1285
  uxLog("action", this, c.cyan(c.italic(`Please see detailed XLSX log in ${c.bold(xslxFile)}`)));
1304
1286
  const xlsFileTitle = options?.fileTitle ? `${options.fileTitle} (XLSX)` : options?.xlsFileTitle ?? "Report (XLSX)";
1305
1287
  WebSocketClient.sendReportFileMessage(xslxFile, xlsFileTitle, "report");
@@ -1318,7 +1300,7 @@ export async function createXlsxFromCsvFiles(csvFilesPath, outputPath, options)
1318
1300
  uxLog("warning", this, c.yellow('Error while generating XLSX log file:\n' + e2.message + '\n' + e2.stack));
1319
1301
  }
1320
1302
  }
1321
- async function csvFilesToXls(csvFiles, xslxFile) {
1303
+ async function csvFilesToXls(csvFiles, xslxFile, options) {
1322
1304
  const workbook = new ExcelJS.Workbook();
1323
1305
  let worksheet;
1324
1306
  for (const csvFile of csvFiles) {
@@ -1328,24 +1310,7 @@ async function csvFilesToXls(csvFiles, xslxFile) {
1328
1310
  }
1329
1311
  worksheet = await workbook.csv.readFile(csvFile);
1330
1312
  worksheet.name = path.basename(csvFile).replace('.csv', '').substring(0, 25);
1331
- // Set filters
1332
- worksheet.autoFilter = 'A1:Z1';
1333
- // Adjust column size (only if the file is not too big, to avoid performances issues)
1334
- if (worksheet.rowCount < 5000) {
1335
- if (!worksheet.columns) {
1336
- console.error(`[csvFilesToXls] worksheet.columns is null for file: ${csvFile}`);
1337
- continue;
1338
- }
1339
- worksheet.columns.forEach((column, idx) => {
1340
- if (!column) {
1341
- console.error(`[csvFilesToXls] Null column at index ${idx} in file: ${csvFile}`);
1342
- return;
1343
- }
1344
- const lengths = (column.values || []).map((v) => (v || '').toString().length);
1345
- const maxLength = Math.max(...lengths.filter((v) => typeof v === 'number'));
1346
- column.width = maxLength;
1347
- });
1348
- }
1313
+ applyWorksheetFormatting(worksheet, options);
1349
1314
  // Scan only the first row and convert string formulas
1350
1315
  const firstRow = worksheet.getRow(1);
1351
1316
  firstRow.eachCell((cell) => {
@@ -1356,4 +1321,110 @@ async function csvFilesToXls(csvFiles, xslxFile) {
1356
1321
  }
1357
1322
  await workbook.xlsx.writeFile(xslxFile);
1358
1323
  }
1324
+ function applyWorksheetFormatting(worksheet, options) {
1325
+ worksheet.autoFilter = 'A1:Z1';
1326
+ if (!worksheet.columns) {
1327
+ return;
1328
+ }
1329
+ const columnStylePreferences = new Map();
1330
+ const columnMaxHeightConstraints = new Map();
1331
+ Object.entries(options?.columnsCustomStyles ?? {}).forEach(([columnName, style]) => {
1332
+ if (!columnName || !style) {
1333
+ return;
1334
+ }
1335
+ const normalizedName = columnName.trim().toLowerCase();
1336
+ const sanitizedStyle = {
1337
+ wrap: style.wrap === true,
1338
+ width: typeof style.width === 'number' && style.width > 0 ? style.width : undefined,
1339
+ hyperlinkFromValue: style.hyperlinkFromValue === true,
1340
+ maxHeight: typeof style.maxHeight === 'number' && style.maxHeight > 0 ? style.maxHeight : undefined,
1341
+ };
1342
+ columnStylePreferences.set(normalizedName, sanitizedStyle);
1343
+ });
1344
+ const headerRow = worksheet.getRow(1);
1345
+ const headerByColumn = new Map();
1346
+ headerRow.eachCell({ includeEmpty: true }, (cell, colNumber) => {
1347
+ const headerValue = (cell?.text ?? (cell.value ?? '')).toString();
1348
+ headerByColumn.set(colNumber, headerValue);
1349
+ });
1350
+ const shouldAutoFit = worksheet.rowCount < 5000;
1351
+ worksheet.columns.forEach((column, idx) => {
1352
+ if (!column) {
1353
+ return;
1354
+ }
1355
+ const columnNumber = column.number ?? idx + 1;
1356
+ const headerName = headerByColumn.get(columnNumber) ?? '';
1357
+ const normalizedHeader = headerName.trim().toLowerCase();
1358
+ const stylePreferences = columnStylePreferences.get(normalizedHeader);
1359
+ const preferredWidth = stylePreferences?.width;
1360
+ if (typeof preferredWidth === 'number') {
1361
+ column.width = preferredWidth;
1362
+ }
1363
+ else if (shouldAutoFit) {
1364
+ const lengths = (column.values || []).map((value) => (value ?? '').toString().length);
1365
+ const filteredLengths = lengths.filter((len) => Number.isFinite(len));
1366
+ const maxLength = filteredLengths.length > 0 ? Math.max(...filteredLengths) : 10;
1367
+ column.width = maxLength;
1368
+ }
1369
+ if (stylePreferences?.wrap) {
1370
+ const updatedAlignment = { ...(column.alignment || {}), wrapText: true };
1371
+ column.alignment = updatedAlignment;
1372
+ column.eachCell?.({ includeEmpty: true }, (cell) => {
1373
+ cell.alignment = { ...(cell.alignment || {}), wrapText: true };
1374
+ });
1375
+ }
1376
+ if (stylePreferences?.hyperlinkFromValue) {
1377
+ column.eachCell?.({ includeEmpty: true }, (cell) => {
1378
+ const hyperlinkTarget = extractHyperlinkTarget(cell);
1379
+ if (!hyperlinkTarget) {
1380
+ return;
1381
+ }
1382
+ const textValue = cell.text?.trim() || hyperlinkTarget;
1383
+ cell.value = { text: textValue, hyperlink: hyperlinkTarget };
1384
+ cell.font = { ...(cell.font || {}), color: { argb: 'FF0563C1' }, underline: true };
1385
+ });
1386
+ }
1387
+ if (stylePreferences?.maxHeight && columnNumber) {
1388
+ columnMaxHeightConstraints.set(columnNumber, stylePreferences.maxHeight);
1389
+ }
1390
+ });
1391
+ if (columnMaxHeightConstraints.size > 0) {
1392
+ worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
1393
+ if (rowNumber === 1 || !row) {
1394
+ return;
1395
+ }
1396
+ let enforcedMaxHeight;
1397
+ columnMaxHeightConstraints.forEach((maxHeight, columnNumber) => {
1398
+ const cell = row.getCell(columnNumber);
1399
+ if (!cell) {
1400
+ return;
1401
+ }
1402
+ const hasValue = cell.value !== null && cell.value !== undefined && cell.value !== '';
1403
+ if (!hasValue) {
1404
+ return;
1405
+ }
1406
+ enforcedMaxHeight = typeof enforcedMaxHeight === 'number' ? Math.min(enforcedMaxHeight, maxHeight) : maxHeight;
1407
+ });
1408
+ if (typeof enforcedMaxHeight === 'number') {
1409
+ if (!row.height || row.height > enforcedMaxHeight) {
1410
+ row.height = enforcedMaxHeight;
1411
+ }
1412
+ }
1413
+ });
1414
+ }
1415
+ }
1416
+ function extractHyperlinkTarget(cell) {
1417
+ const rawValue = typeof cell.value === 'string' ? cell.value : cell.text;
1418
+ if (!rawValue) {
1419
+ return null;
1420
+ }
1421
+ const trimmed = rawValue.trim();
1422
+ if (!trimmed) {
1423
+ return null;
1424
+ }
1425
+ return isLikelyHyperlink(trimmed) ? trimmed : null;
1426
+ }
1427
+ function isLikelyHyperlink(value) {
1428
+ return /^(https?:\/\/|mailto:)/i.test(value);
1429
+ }
1359
1430
  //# sourceMappingURL=filesUtils.js.map