@cloudstrytech/validations 1.0.9 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/csv/csvValidator.js +7 -1
- package/src/csv/parseCsv.js +70 -12
- package/src/index.js +1 -0
- package/src/validators/dateValidator.js +22 -4
- package/src/validators/normalizeDate.js +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudstrytech/validations",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "JavaScript utility functions for validation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"author": "Cloudstry",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"papaparse": "^5.5.3"
|
|
16
|
+
"papaparse": "^5.5.3",
|
|
17
|
+
"xlsx": "^0.18.5"
|
|
17
18
|
}
|
|
18
19
|
}
|
package/src/csv/csvValidator.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// csvValidator.js file
|
|
2
2
|
|
|
3
|
-
import { parseCSV } from "./
|
|
3
|
+
import { parseCSV } from "./parseCSV.js";
|
|
4
4
|
import { isValidEmail } from "../validators/emailValidator.js";
|
|
5
5
|
import { isValidIndianMobile } from "../validators/mobileValidator.js";
|
|
6
6
|
import { isValidDate } from "../validators/dateValidator.js";
|
|
7
|
+
import { normalizeDate } from "../validators/normalizeDate.js";
|
|
7
8
|
|
|
8
9
|
/* Normalize CSV headers */
|
|
9
10
|
function normalizeKey(key = "") {
|
|
@@ -77,6 +78,11 @@ export async function validateCSV(csvInput) {
|
|
|
77
78
|
|
|
78
79
|
return {
|
|
79
80
|
...row,
|
|
81
|
+
"issuedate-b1":
|
|
82
|
+
messages.length === 0
|
|
83
|
+
? normalizeDate(normalizedRow["issuedate-b1"])
|
|
84
|
+
: row["issuedate-b1"],
|
|
85
|
+
|
|
80
86
|
__status: messages.length > 0 ? "ERROR" : "SUCCESS",
|
|
81
87
|
__messages: messages.length > 0 ? messages : [],
|
|
82
88
|
};
|
package/src/csv/parseCsv.js
CHANGED
|
@@ -1,41 +1,99 @@
|
|
|
1
1
|
import Papa from "papaparse";
|
|
2
|
+
import * as XLSX from "xlsx";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
|
-
* Parse CSV from File or string
|
|
5
|
+
* Parse CSV / Excel from File or string
|
|
5
6
|
* @param {File | string} input
|
|
6
7
|
* @returns {Promise<Array<Object>>}
|
|
7
8
|
*/
|
|
8
9
|
export function parseCSV(input) {
|
|
9
10
|
return new Promise((resolve, reject) => {
|
|
10
11
|
if (!input) {
|
|
11
|
-
reject(new Error("
|
|
12
|
+
reject(new Error("File input is required"));
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
/* ================= FILE UPLOAD ================= */
|
|
16
17
|
if (typeof File !== "undefined" && input instanceof File) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
const fileName = input.name.toLowerCase();
|
|
19
|
+
|
|
20
|
+
/* 🔒 1️⃣ FILE SIZE LIMIT (ADD HERE) */
|
|
21
|
+
const MAX_SIZE = 5 * 1024 * 1024; // 5MB
|
|
22
|
+
if (input.size > MAX_SIZE) {
|
|
23
|
+
reject(new Error("File too large. Max 5MB allowed."));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* ================= CSV ================= */
|
|
28
|
+
if (fileName.endsWith(".csv")) {
|
|
29
|
+
Papa.parse(input, {
|
|
30
|
+
header: true,
|
|
31
|
+
skipEmptyLines: true,
|
|
32
|
+
complete: (result) => resolve(result.data),
|
|
33
|
+
error: reject,
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ================= XLS / XLSX ================= */
|
|
39
|
+
if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
|
|
40
|
+
const reader = new FileReader();
|
|
41
|
+
|
|
42
|
+
reader.onload = (e) => {
|
|
43
|
+
const data = new Uint8Array(e.target.result);
|
|
44
|
+
|
|
45
|
+
/* 🔒 2️⃣ DISABLE FORMULAS & UNSAFE FEATURES (ADD HERE) */
|
|
46
|
+
const workbook = XLSX.read(data, {
|
|
47
|
+
type: "array",
|
|
48
|
+
cellFormula: false,
|
|
49
|
+
cellHTML: false,
|
|
50
|
+
cellText: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const sheetName = workbook.SheetNames[0]; // first sheet only
|
|
54
|
+
const worksheet = workbook.Sheets[sheetName];
|
|
55
|
+
|
|
56
|
+
/* 🔒 3️⃣ SAFE sheet_to_json (ADD HERE) */
|
|
57
|
+
const json = XLSX.utils.sheet_to_json(worksheet, {
|
|
58
|
+
defval: "",
|
|
59
|
+
raw: false,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/* (Optional but recommended) Row limit */
|
|
63
|
+
if (json.length > 5000) {
|
|
64
|
+
reject(new Error("Too many rows. Max 5000 allowed."));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
resolve(json);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
reader.onerror = () =>
|
|
72
|
+
reject(new Error("Failed to read Excel file"));
|
|
73
|
+
|
|
74
|
+
reader.readAsArrayBuffer(input);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
reject(
|
|
79
|
+
new Error("Unsupported file type. Only CSV, XLS, XLSX allowed.")
|
|
80
|
+
);
|
|
23
81
|
return;
|
|
24
82
|
}
|
|
25
83
|
|
|
26
|
-
|
|
84
|
+
/* ================= CSV STRING ================= */
|
|
27
85
|
if (typeof input === "string") {
|
|
28
86
|
Papa.parse(input, {
|
|
29
87
|
header: true,
|
|
30
88
|
skipEmptyLines: true,
|
|
31
89
|
complete: (result) => resolve(result.data),
|
|
32
|
-
error: reject
|
|
90
|
+
error: reject,
|
|
33
91
|
});
|
|
34
92
|
return;
|
|
35
93
|
}
|
|
36
94
|
|
|
37
95
|
reject(
|
|
38
|
-
new Error("Invalid
|
|
96
|
+
new Error("Invalid input. Provide CSV string or Excel/CSV file.")
|
|
39
97
|
);
|
|
40
98
|
});
|
|
41
99
|
}
|
package/src/index.js
CHANGED
|
@@ -2,3 +2,4 @@ export { isValidEmail } from "./validators/emailValidator.js";
|
|
|
2
2
|
export { isValidIndianMobile } from "./validators/mobileValidator.js";
|
|
3
3
|
export { isValidDate } from "./validators/dateValidator.js";
|
|
4
4
|
export { validateCSV } from "./csv/csvValidator.js";
|
|
5
|
+
export {isValidName} from "./validators/nameValidator.js"
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
export function isValidDate(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
2
|
+
if (!value) return false;
|
|
3
|
+
|
|
4
|
+
// D/M/YY, DD/MM/YY, D/M/YYYY, DD/MM/YYYY
|
|
5
|
+
const regex = /^(\d{1,2})\/(\d{1,2})\/(\d{2}|\d{4})$/;
|
|
6
|
+
const match = value.match(regex);
|
|
7
|
+
if (!match) return false;
|
|
8
|
+
|
|
9
|
+
let [, day, month, year] = match;
|
|
10
|
+
day = parseInt(day, 10);
|
|
11
|
+
month = parseInt(month, 10);
|
|
12
|
+
year = parseInt(year, 10);
|
|
6
13
|
|
|
14
|
+
// Convert 2-digit year → 2000+
|
|
15
|
+
if (year < 100) year += 2000;
|
|
16
|
+
|
|
17
|
+
const date = new Date(year, month - 1, day);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
date.getFullYear() === year &&
|
|
21
|
+
date.getMonth() === month - 1 &&
|
|
22
|
+
date.getDate() === day
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function normalizeDate(value) {
|
|
2
|
+
if (!value) return null;
|
|
3
|
+
|
|
4
|
+
const regex = /^(\d{1,2})\/(\d{1,2})\/(\d{2}|\d{4})$/;
|
|
5
|
+
const match = value.match(regex);
|
|
6
|
+
if (!match) return null;
|
|
7
|
+
|
|
8
|
+
let [, day, month, year] = match;
|
|
9
|
+
|
|
10
|
+
day = String(day).padStart(2, "0");
|
|
11
|
+
month = String(month).padStart(2, "0");
|
|
12
|
+
year = year.length === 2 ? `20${year}` : year;
|
|
13
|
+
|
|
14
|
+
return `${day}/${month}/${year}`;
|
|
15
|
+
}
|