@lichens-innovation/ts-common 1.17.0 → 1.18.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/dist/csv.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mime/index.ts","../src/csv/index.ts"],"names":["mime","Papa"],"mappings":";;;;;;;;;;;AA2CO,IAAM,WAAA,GAAc,CAAC,SAAA,KAA8B;AACxD,EAAA,MAAM,QAAA,GAAWA,qBAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AACvC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kDAAA,EAAqD,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACnF;AAEA,EAAA,OAAO,QAAA;AACT,CAAA;;;AC7CO,IAAM,eAAA,GAAkB,CAAC,GAAA,KAA2D;AACzF,EAAA,MAAM,YAAoC,EAAC;AAE3C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,SAAA,CAAU,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,SAAA;AACT;AAEO,IAAM,eAAA,GAAkB,CAAC,IAAA,KAA4C;AAC1E,EAAA,MAAM,IAAA,GAAiC,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAMC,sBAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,GAAA,EAAK,CAAA;AAE/D,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,GAAG,CAAA,EAAG,EAAE,IAAA,EAAM,WAAA,CAAY,KAAK,CAAA,EAAG,CAAA;AACrD","file":"csv.cjs","sourcesContent":["import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from \"./mime.utils\";\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import Papa from \"papaparse\";\nimport { getMimeType } from \"../mime\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport const convertToCsvRow = (row: Record<string, CellValue>): Record<string, string> => {\n const stringRow: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(row)) {\n stringRow[key] = String(value ?? \"\");\n }\n\n return stringRow;\n};\n\nexport const generateCsvBlob = (data: Record<string, CellValue>[]): Blob => {\n const rows: Record<string, string>[] = data.map(convertToCsvRow);\n const csv = Papa.unparse(rows, { header: true, delimiter: \",\" });\n\n return new Blob([csv], { type: getMimeType(\"csv\") });\n};\n"]}
1
+ {"version":3,"sources":["../src/mime/index.ts","../src/csv/index.ts"],"names":["mime","Papa"],"mappings":";;;;;;;;;;;AAwDO,IAAM,WAAA,GAAc,CAAC,SAAA,KAA8B;AACxD,EAAA,MAAM,QAAA,GAAWA,qBAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AACvC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kDAAA,EAAqD,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACnF;AAEA,EAAA,OAAO,QAAA;AACT,CAAA;;;AC1DO,IAAM,eAAA,GAAkB,CAAC,GAAA,KAA2D;AACzF,EAAA,MAAM,YAAoC,EAAC;AAE3C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,SAAA,CAAU,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,SAAA;AACT;AAEO,IAAM,eAAA,GAAkB,CAAC,IAAA,KAA4C;AAC1E,EAAA,MAAM,IAAA,GAAiC,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAMC,sBAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,GAAA,EAAK,CAAA;AAE/D,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,GAAG,CAAA,EAAG,EAAE,IAAA,EAAM,WAAA,CAAY,KAAK,CAAA,EAAG,CAAA;AACrD","file":"csv.cjs","sourcesContent":["import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const isValidImageFile = (file: { type: string }): boolean => {\n return isImageMimeType(file.type);\n};\n\nexport const getExtensionFromDataUri = (dataUri: string): string => {\n const parsed = parseDataUri(dataUri);\n if (!parsed) return 'bin';\n\n return parsed.ext;\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import Papa from \"papaparse\";\nimport { getMimeType } from \"../mime\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport const convertToCsvRow = (row: Record<string, CellValue>): Record<string, string> => {\n const stringRow: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(row)) {\n stringRow[key] = String(value ?? \"\");\n }\n\n return stringRow;\n};\n\nexport const generateCsvBlob = (data: Record<string, CellValue>[]): Blob => {\n const rows: Record<string, string>[] = data.map(convertToCsvRow);\n const csv = Papa.unparse(rows, { header: true, delimiter: \",\" });\n\n return new Blob([csv], { type: getMimeType(\"csv\") });\n};\n"]}
package/dist/csv.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mime/index.ts","../src/csv/index.ts"],"names":[],"mappings":";;;;AA2CO,IAAM,WAAA,GAAc,CAAC,SAAA,KAA8B;AACxD,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AACvC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kDAAA,EAAqD,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACnF;AAEA,EAAA,OAAO,QAAA;AACT,CAAA;;;AC7CO,IAAM,eAAA,GAAkB,CAAC,GAAA,KAA2D;AACzF,EAAA,MAAM,YAAoC,EAAC;AAE3C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,SAAA,CAAU,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,SAAA;AACT;AAEO,IAAM,eAAA,GAAkB,CAAC,IAAA,KAA4C;AAC1E,EAAA,MAAM,IAAA,GAAiC,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,KAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,GAAA,EAAK,CAAA;AAE/D,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,GAAG,CAAA,EAAG,EAAE,IAAA,EAAM,WAAA,CAAY,KAAK,CAAA,EAAG,CAAA;AACrD","file":"csv.js","sourcesContent":["import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from \"./mime.utils\";\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import Papa from \"papaparse\";\nimport { getMimeType } from \"../mime\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport const convertToCsvRow = (row: Record<string, CellValue>): Record<string, string> => {\n const stringRow: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(row)) {\n stringRow[key] = String(value ?? \"\");\n }\n\n return stringRow;\n};\n\nexport const generateCsvBlob = (data: Record<string, CellValue>[]): Blob => {\n const rows: Record<string, string>[] = data.map(convertToCsvRow);\n const csv = Papa.unparse(rows, { header: true, delimiter: \",\" });\n\n return new Blob([csv], { type: getMimeType(\"csv\") });\n};\n"]}
1
+ {"version":3,"sources":["../src/mime/index.ts","../src/csv/index.ts"],"names":[],"mappings":";;;;AAwDO,IAAM,WAAA,GAAc,CAAC,SAAA,KAA8B;AACxD,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,SAAS,CAAA;AACvC,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kDAAA,EAAqD,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EACnF;AAEA,EAAA,OAAO,QAAA;AACT,CAAA;;;AC1DO,IAAM,eAAA,GAAkB,CAAC,GAAA,KAA2D;AACzF,EAAA,MAAM,YAAoC,EAAC;AAE3C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,SAAA,CAAU,GAAG,CAAA,GAAI,MAAA,CAAO,KAAA,IAAS,EAAE,CAAA;AAAA,EACrC;AAEA,EAAA,OAAO,SAAA;AACT;AAEO,IAAM,eAAA,GAAkB,CAAC,IAAA,KAA4C;AAC1E,EAAA,MAAM,IAAA,GAAiC,IAAA,CAAK,GAAA,CAAI,eAAe,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,KAAK,OAAA,CAAQ,IAAA,EAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW,GAAA,EAAK,CAAA;AAE/D,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,GAAG,CAAA,EAAG,EAAE,IAAA,EAAM,WAAA,CAAY,KAAK,CAAA,EAAG,CAAA;AACrD","file":"csv.js","sourcesContent":["import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const isValidImageFile = (file: { type: string }): boolean => {\n return isImageMimeType(file.type);\n};\n\nexport const getExtensionFromDataUri = (dataUri: string): string => {\n const parsed = parseDataUri(dataUri);\n if (!parsed) return 'bin';\n\n return parsed.ext;\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import Papa from \"papaparse\";\nimport { getMimeType } from \"../mime\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport const convertToCsvRow = (row: Record<string, CellValue>): Record<string, string> => {\n const stringRow: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(row)) {\n stringRow[key] = String(value ?? \"\");\n }\n\n return stringRow;\n};\n\nexport const generateCsvBlob = (data: Record<string, CellValue>[]): Blob => {\n const rows: Record<string, string>[] = data.map(convertToCsvRow);\n const csv = Papa.unparse(rows, { header: true, delimiter: \",\" });\n\n return new Blob([csv], { type: getMimeType(\"csv\") });\n};\n"]}
@@ -0,0 +1,47 @@
1
+ interface RgbColor {
2
+ r: number;
3
+ g: number;
4
+ b: number;
5
+ }
6
+ interface RgbaColor extends RgbColor {
7
+ a: number;
8
+ }
9
+ declare const rgbToHex: (r: number, g: number, b: number) => string;
10
+ declare const hexToRgb: (hex: string) => RgbColor;
11
+ declare const rgbaToHex: (color: RgbaColor) => string;
12
+ declare const getOpacityHexValue: (opacity: number) => string;
13
+ declare const rgbaToHexWithAlpha: (color: RgbaColor) => string;
14
+ declare const rgbToString: (color: RgbColor) => string;
15
+ declare const rgbaToString: (color: RgbaColor) => string;
16
+ declare const getLuminance: (r: number, g: number, b: number) => number;
17
+ declare const getContrastTextColor: (hexColor: string) => string;
18
+ /**
19
+ * Normalized RGB color with values between 0 and 1.
20
+ * Useful for graphics libraries like Three.js.
21
+ */
22
+ interface NormalizedRgb {
23
+ r: number;
24
+ g: number;
25
+ b: number;
26
+ }
27
+ /**
28
+ * Convert a hex color string to normalized RGB values (0-1 range).
29
+ * @param hex - Hex color string (with or without # prefix)
30
+ * @returns Normalized RGB object with values between 0 and 1
31
+ */
32
+ declare const hexToNormalizedRgb: (hex: string) => NormalizedRgb;
33
+ /**
34
+ * Determine if a color is light or dark based on relative luminance.
35
+ * Useful for choosing contrasting text colors.
36
+ * @param hex - Hex color string
37
+ * @returns True if the color is considered light (luminance > 0.5)
38
+ */
39
+ declare const isLightColor: (hex: string) => boolean;
40
+ declare const getColorForPercentage: (percent: number) => string;
41
+
42
+ interface Dimensions {
43
+ width: number;
44
+ height: number;
45
+ }
46
+
47
+ export { type Dimensions as D, type NormalizedRgb as N, type RgbColor as R, type RgbaColor as a, rgbaToHex as b, rgbaToHexWithAlpha as c, rgbToString as d, rgbaToString as e, getLuminance as f, getOpacityHexValue as g, hexToRgb as h, getContrastTextColor as i, hexToNormalizedRgb as j, isLightColor as k, getColorForPercentage as l, rgbToHex as r };
@@ -0,0 +1,47 @@
1
+ interface RgbColor {
2
+ r: number;
3
+ g: number;
4
+ b: number;
5
+ }
6
+ interface RgbaColor extends RgbColor {
7
+ a: number;
8
+ }
9
+ declare const rgbToHex: (r: number, g: number, b: number) => string;
10
+ declare const hexToRgb: (hex: string) => RgbColor;
11
+ declare const rgbaToHex: (color: RgbaColor) => string;
12
+ declare const getOpacityHexValue: (opacity: number) => string;
13
+ declare const rgbaToHexWithAlpha: (color: RgbaColor) => string;
14
+ declare const rgbToString: (color: RgbColor) => string;
15
+ declare const rgbaToString: (color: RgbaColor) => string;
16
+ declare const getLuminance: (r: number, g: number, b: number) => number;
17
+ declare const getContrastTextColor: (hexColor: string) => string;
18
+ /**
19
+ * Normalized RGB color with values between 0 and 1.
20
+ * Useful for graphics libraries like Three.js.
21
+ */
22
+ interface NormalizedRgb {
23
+ r: number;
24
+ g: number;
25
+ b: number;
26
+ }
27
+ /**
28
+ * Convert a hex color string to normalized RGB values (0-1 range).
29
+ * @param hex - Hex color string (with or without # prefix)
30
+ * @returns Normalized RGB object with values between 0 and 1
31
+ */
32
+ declare const hexToNormalizedRgb: (hex: string) => NormalizedRgb;
33
+ /**
34
+ * Determine if a color is light or dark based on relative luminance.
35
+ * Useful for choosing contrasting text colors.
36
+ * @param hex - Hex color string
37
+ * @returns True if the color is considered light (luminance > 0.5)
38
+ */
39
+ declare const isLightColor: (hex: string) => boolean;
40
+ declare const getColorForPercentage: (percent: number) => string;
41
+
42
+ interface Dimensions {
43
+ width: number;
44
+ height: number;
45
+ }
46
+
47
+ export { type Dimensions as D, type NormalizedRgb as N, type RgbColor as R, type RgbaColor as a, rgbaToHex as b, rgbaToHexWithAlpha as c, rgbToString as d, rgbaToString as e, getLuminance as f, getOpacityHexValue as g, hexToRgb as h, getContrastTextColor as i, hexToNormalizedRgb as j, isLightColor as k, getColorForPercentage as l, rgbToHex as r };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/excel/excel-generator.ts","../src/excel/excel-generator.types.ts","../src/utils/types.utils.ts","../src/mime/index.ts","../src/excel/exceljs.utils.ts"],"names":["mime","ExcelJS"],"mappings":"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","file":"excel.cjs","sourcesContent":["import ExcelJS from \"exceljs\";\nimport type { CellStyle, CellValue } from \"./excel-generator.types\";\n\ninterface AddCellArgs {\n row: number;\n col: number;\n value: CellValue;\n style?: CellStyle;\n}\n\ninterface AddRowArgs {\n values: CellValue[];\n styles?: CellStyle[];\n}\n\nexport class WorksheetBuilder {\n private worksheet: ExcelJS.Worksheet;\n private currentRow: number;\n private defaultRowStyles: CellStyle[];\n\n constructor(worksheet: ExcelJS.Worksheet) {\n this.worksheet = worksheet;\n this.currentRow = 1; // ExcelJS uses 1-based indexing\n this.defaultRowStyles = [];\n }\n\n /** Returns the current row index (1-based). */\n get rowCount(): number {\n return this.currentRow;\n }\n\n addCell({ row, col, value, style }: AddCellArgs): void {\n const cell = this.worksheet.getCell(row + 1, col + 1); // Convert to 1-based\n cell.value = value ?? \"\";\n\n if (style) {\n this.applyStyle(cell, style);\n }\n }\n\n addRow({ values, styles }: AddRowArgs): void {\n const stylesToUse = styles ?? this.defaultRowStyles;\n const row = this.worksheet.addRow(values);\n\n // Apply styles to each cell in the row\n for (let col = 0; col < values.length; col++) {\n const style = stylesToUse[col];\n if (style) {\n const cell = row.getCell(col + 1); // ExcelJS uses 1-based indexing\n this.applyStyle(cell, style);\n }\n }\n\n this.currentRow++;\n }\n\n setDefaultRowStyles(styles: CellStyle[]): void {\n this.defaultRowStyles = styles;\n }\n\n addEmptyRow(): void {\n this.worksheet.addRow([]);\n this.currentRow++;\n }\n\n setColumnWidths(columnWidths: number[]): void {\n this.worksheet.columns = columnWidths.map((width) => ({ width }));\n }\n\n getWorksheet(): ExcelJS.Worksheet {\n return this.worksheet;\n }\n\n private applyStyle(cell: ExcelJS.Cell, style: CellStyle): void {\n if (style.font) {\n cell.font = { ...cell.font, ...style.font };\n }\n\n if (style.fill) {\n cell.fill = style.fill as ExcelJS.Fill;\n }\n\n if (style.alignment) {\n cell.alignment = { ...cell.alignment, ...style.alignment };\n }\n\n if (style.border) {\n cell.border = { ...cell.border, ...style.border };\n }\n\n if (style.numFmt) {\n cell.numFmt = style.numFmt;\n }\n }\n}\n","import type { Font, Fill, Alignment } from \"exceljs\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport type VerticalAlignment = \"top\" | \"middle\" | \"bottom\";\nexport type HorizontalAlignment = \"left\" | \"center\" | \"right\";\n\nexport type ColumnValueType = \"number\" | \"text\" | \"auto\";\n\nexport interface ColumnMetadata {\n name: string;\n width: number;\n valueType?: ColumnValueType;\n}\n\ninterface BorderSide {\n style?: \"thin\" | \"medium\" | \"thick\" | \"dotted\" | \"dashed\" | \"double\";\n color?: { argb: string };\n}\n\n/**\n * Type for ExcelJS cell borders.\n */\nexport interface CellBorder {\n top?: BorderSide;\n bottom?: BorderSide;\n left?: BorderSide;\n right?: BorderSide;\n}\n\n/**\n * Type for ExcelJS cell styles.\n * This is a simplified version of ExcelJS.Style that focuses on commonly used properties.\n */\nexport interface CellStyle {\n font?: Partial<Font>;\n fill?: Partial<Fill>;\n alignment?: Partial<Alignment>;\n border?: CellBorder;\n numFmt?: string;\n}\n\n/**\n * Helper type to convert RGB color string to ARGB format for ExcelJS.\n * ExcelJS uses ARGB format: \"FFFFFFFF\" where FF is alpha, then RGB.\n */\nexport type ArgbColor = { argb: string };\n\n/**\n * Helper function to convert RGB color string to ARGB format.\n * @param rgb - RGB color string without # (e.g., \"FFFFFF\")\n * @returns ARGB color object (e.g., { argb: \"FFFFFFFF\" })\n */\nexport const rgbToArgb = (rgb: string): ArgbColor => {\n return { argb: `FF${rgb}` };\n};\n","export const NO_OP: () => void = () => {};\n\nexport const isNullish = (value: unknown): value is null | undefined => value === null || value === undefined;\n\nexport const isNumber = (value?: unknown | null): value is number => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'number') {\n return false;\n }\n\n if (isNaN(value)) {\n return false;\n }\n\n return true;\n};\n\nexport const isString = (value?: unknown | null): value is string => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'string') {\n return false;\n }\n\n return true;\n};\n","import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from \"./mime.utils\";\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import ExcelJS from \"exceljs\";\nimport { getMimeType } from \"../mime\";\nimport { isNullish } from \"../utils\";\nimport type { CellValue, ColumnMetadata } from \"./excel-generator.types\";\n\n/**\n * Sanitizes a worksheet title to comply with Excel's limitations.\n *\n * Excel enforces strict rules for worksheet names:\n * - Maximum length of 31 characters (legacy limitation from older Excel versions)\n * - Certain characters are reserved for special purposes and cannot be used:\n * - `:` (colon) - used in cell range references (e.g., A1:B2)\n * - `/` (forward slash) - used in file paths\n * - `\\` (backslash) - used in file paths and escape sequences\n * - `?` (question mark) - used as wildcard in formulas\n * - `*` (asterisk) - used as wildcard in formulas\n * - `[` and `]` (square brackets) - used in external references (e.g., [Book1.xlsx]Sheet1!A1)\n *\n * This function removes invalid characters and truncates the title to 31 characters\n * to ensure compatibility with Excel's file format specifications.\n *\n * @param title - The original worksheet title to sanitize\n * @returns A sanitized title that complies with Excel's naming rules\n */\nexport const sanitizeWorksheetTitle = (title: string): string => {\n const MAX_LENGTH = 31;\n const INVALID_CHARS = /[:/\\\\?*[\\]]/g;\n\n return title.trim().replace(INVALID_CHARS, \"\").slice(0, MAX_LENGTH);\n};\n\ninterface ToSafeCellValueArgs {\n value: CellValue;\n valueType: ColumnMetadata[\"valueType\"];\n}\n\nconst toSafeCellValue = ({ value, valueType }: ToSafeCellValueArgs): CellValue => {\n if (!isNullish(value) && valueType === \"number\") {\n const numValue = typeof value === \"number\" ? value : Number(value);\n return isNaN(numValue) ? value : numValue;\n }\n\n return value ?? \"\";\n};\n\ninterface ToSafeCellValuesArgs {\n headers: string[];\n rowData: Record<string, CellValue>;\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst toSafeCellValues = ({ headers, rowData, columnsMetadata }: ToSafeCellValuesArgs): CellValue[] => {\n return headers.map((header) => {\n const value = rowData[header];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n return toSafeCellValue({ value, valueType });\n });\n};\n\ninterface ApplyTextFormattingArgs {\n row: ExcelJS.Row;\n headers: string[];\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst applyTextFormatting = ({ row, headers, columnsMetadata }: ApplyTextFormattingArgs): void => {\n for (let colIndex = 0; colIndex < headers.length; colIndex++) {\n const header = headers[colIndex];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n\n if (valueType === \"text\") {\n const cell = row.getCell(colIndex + 1);\n cell.numFmt = \"@\";\n }\n }\n};\n\nconst applyHeaderStyles = (headerRow: ExcelJS.Row): void => {\n headerRow.font = { bold: true };\n headerRow.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"FFE0E0E0\" },\n };\n headerRow.alignment = { wrapText: true, vertical: \"top\" };\n};\n\ninterface SetupHeaderFrozenRowArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n}\n\nconst setupHeaderFrozenRow = ({ worksheet, headers }: SetupHeaderFrozenRowArgs): void => {\n const headerRow = worksheet.addRow(headers);\n applyHeaderStyles(headerRow);\n worksheet.views = [{ state: \"frozen\", ySplit: 1 }];\n};\n\ninterface ApplyDataRowStylesArgs {\n worksheet: ExcelJS.Worksheet;\n startRowIndex: number;\n endRowIndex: number;\n}\n\nconst applyDataRowStyles = ({ worksheet, startRowIndex, endRowIndex }: ApplyDataRowStylesArgs): void => {\n for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {\n const row = worksheet.getRow(rowIndex);\n row.alignment = { wrapText: false, vertical: \"top\" };\n }\n};\n\ninterface SetColumnWidthsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nconst setColumnWidths = ({ worksheet, headers, columnsMetadata }: SetColumnWidthsArgs): void => {\n worksheet.columns = headers.map((header) => {\n const metadata = columnsMetadata[header];\n return metadata ? { width: metadata.width } : {};\n });\n};\n\ninterface AddDataRowsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n data: Record<string, CellValue>[];\n}\n\nconst addDataRows = ({ worksheet, headers, columnsMetadata, data }: AddDataRowsArgs): void => {\n for (const rowData of data) {\n const safeCellValues = toSafeCellValues({ headers, rowData, columnsMetadata });\n const row = worksheet.addRow(safeCellValues);\n applyTextFormatting({ row, headers, columnsMetadata });\n }\n\n applyDataRowStyles({ worksheet, startRowIndex: 2, endRowIndex: data.length + 1 });\n};\n\ninterface GenerateExcelBlobArgs {\n worksheetTitle: string;\n data: Record<string, CellValue>[];\n /**\n * Metadata for columns, keyed by column name (translated header name).\n * If not provided, columns will use default width and auto-detect value types.\n */\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nexport const generateExcelBlob = async (args: GenerateExcelBlobArgs): Promise<Blob> => {\n const { data, columnsMetadata, worksheetTitle } = args;\n\n if (data.length === 0) {\n throw new Error(\"No data to export\");\n }\n\n const headers = Object.keys(data[0]);\n const workbook = new ExcelJS.Workbook();\n const worksheet = workbook.addWorksheet(sanitizeWorksheetTitle(worksheetTitle));\n\n setupHeaderFrozenRow({ worksheet, headers });\n addDataRows({ worksheet, headers, columnsMetadata, data });\n setColumnWidths({ worksheet, headers, columnsMetadata });\n\n const buffer = await workbook.xlsx.writeBuffer();\n return new Blob([buffer], { type: getMimeType(\"xlsx\") });\n};\n"]}
1
+ {"version":3,"sources":["../src/excel/excel-generator.ts","../src/excel/excel-generator.types.ts","../src/utils/types.utils.ts","../src/mime/index.ts","../src/excel/exceljs.utils.ts"],"names":["mime","ExcelJS"],"mappings":"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","file":"excel.cjs","sourcesContent":["import ExcelJS from \"exceljs\";\nimport type { CellStyle, CellValue } from \"./excel-generator.types\";\n\ninterface AddCellArgs {\n row: number;\n col: number;\n value: CellValue;\n style?: CellStyle;\n}\n\ninterface AddRowArgs {\n values: CellValue[];\n styles?: CellStyle[];\n}\n\nexport class WorksheetBuilder {\n private worksheet: ExcelJS.Worksheet;\n private currentRow: number;\n private defaultRowStyles: CellStyle[];\n\n constructor(worksheet: ExcelJS.Worksheet) {\n this.worksheet = worksheet;\n this.currentRow = 1; // ExcelJS uses 1-based indexing\n this.defaultRowStyles = [];\n }\n\n /** Returns the current row index (1-based). */\n get rowCount(): number {\n return this.currentRow;\n }\n\n addCell({ row, col, value, style }: AddCellArgs): void {\n const cell = this.worksheet.getCell(row + 1, col + 1); // Convert to 1-based\n cell.value = value ?? \"\";\n\n if (style) {\n this.applyStyle(cell, style);\n }\n }\n\n addRow({ values, styles }: AddRowArgs): void {\n const stylesToUse = styles ?? this.defaultRowStyles;\n const row = this.worksheet.addRow(values);\n\n // Apply styles to each cell in the row\n for (let col = 0; col < values.length; col++) {\n const style = stylesToUse[col];\n if (style) {\n const cell = row.getCell(col + 1); // ExcelJS uses 1-based indexing\n this.applyStyle(cell, style);\n }\n }\n\n this.currentRow++;\n }\n\n setDefaultRowStyles(styles: CellStyle[]): void {\n this.defaultRowStyles = styles;\n }\n\n addEmptyRow(): void {\n this.worksheet.addRow([]);\n this.currentRow++;\n }\n\n setColumnWidths(columnWidths: number[]): void {\n this.worksheet.columns = columnWidths.map((width) => ({ width }));\n }\n\n getWorksheet(): ExcelJS.Worksheet {\n return this.worksheet;\n }\n\n private applyStyle(cell: ExcelJS.Cell, style: CellStyle): void {\n if (style.font) {\n cell.font = { ...cell.font, ...style.font };\n }\n\n if (style.fill) {\n cell.fill = style.fill as ExcelJS.Fill;\n }\n\n if (style.alignment) {\n cell.alignment = { ...cell.alignment, ...style.alignment };\n }\n\n if (style.border) {\n cell.border = { ...cell.border, ...style.border };\n }\n\n if (style.numFmt) {\n cell.numFmt = style.numFmt;\n }\n }\n}\n","import type { Font, Fill, Alignment } from \"exceljs\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport type VerticalAlignment = \"top\" | \"middle\" | \"bottom\";\nexport type HorizontalAlignment = \"left\" | \"center\" | \"right\";\n\nexport type ColumnValueType = \"number\" | \"text\" | \"auto\";\n\nexport interface ColumnMetadata {\n name: string;\n width: number;\n valueType?: ColumnValueType;\n}\n\ninterface BorderSide {\n style?: \"thin\" | \"medium\" | \"thick\" | \"dotted\" | \"dashed\" | \"double\";\n color?: { argb: string };\n}\n\n/**\n * Type for ExcelJS cell borders.\n */\nexport interface CellBorder {\n top?: BorderSide;\n bottom?: BorderSide;\n left?: BorderSide;\n right?: BorderSide;\n}\n\n/**\n * Type for ExcelJS cell styles.\n * This is a simplified version of ExcelJS.Style that focuses on commonly used properties.\n */\nexport interface CellStyle {\n font?: Partial<Font>;\n fill?: Partial<Fill>;\n alignment?: Partial<Alignment>;\n border?: CellBorder;\n numFmt?: string;\n}\n\n/**\n * Helper type to convert RGB color string to ARGB format for ExcelJS.\n * ExcelJS uses ARGB format: \"FFFFFFFF\" where FF is alpha, then RGB.\n */\nexport type ArgbColor = { argb: string };\n\n/**\n * Helper function to convert RGB color string to ARGB format.\n * @param rgb - RGB color string without # (e.g., \"FFFFFF\")\n * @returns ARGB color object (e.g., { argb: \"FFFFFFFF\" })\n */\nexport const rgbToArgb = (rgb: string): ArgbColor => {\n return { argb: `FF${rgb}` };\n};\n","export const NO_OP: () => void = () => {};\n\nexport const isNullish = (value: unknown): value is null | undefined => value === null || value === undefined;\n\nexport const isNumber = (value?: unknown | null): value is number => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'number') {\n return false;\n }\n\n if (isNaN(value)) {\n return false;\n }\n\n return true;\n};\n\nexport const isString = (value?: unknown | null): value is string => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'string') {\n return false;\n }\n\n return true;\n};\n","import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const isValidImageFile = (file: { type: string }): boolean => {\n return isImageMimeType(file.type);\n};\n\nexport const getExtensionFromDataUri = (dataUri: string): string => {\n const parsed = parseDataUri(dataUri);\n if (!parsed) return 'bin';\n\n return parsed.ext;\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import ExcelJS from \"exceljs\";\nimport { getMimeType } from \"../mime\";\nimport { isNullish } from \"../utils\";\nimport type { CellValue, ColumnMetadata } from \"./excel-generator.types\";\n\n/**\n * Sanitizes a worksheet title to comply with Excel's limitations.\n *\n * Excel enforces strict rules for worksheet names:\n * - Maximum length of 31 characters (legacy limitation from older Excel versions)\n * - Certain characters are reserved for special purposes and cannot be used:\n * - `:` (colon) - used in cell range references (e.g., A1:B2)\n * - `/` (forward slash) - used in file paths\n * - `\\` (backslash) - used in file paths and escape sequences\n * - `?` (question mark) - used as wildcard in formulas\n * - `*` (asterisk) - used as wildcard in formulas\n * - `[` and `]` (square brackets) - used in external references (e.g., [Book1.xlsx]Sheet1!A1)\n *\n * This function removes invalid characters and truncates the title to 31 characters\n * to ensure compatibility with Excel's file format specifications.\n *\n * @param title - The original worksheet title to sanitize\n * @returns A sanitized title that complies with Excel's naming rules\n */\nexport const sanitizeWorksheetTitle = (title: string): string => {\n const MAX_LENGTH = 31;\n const INVALID_CHARS = /[:/\\\\?*[\\]]/g;\n\n return title.trim().replace(INVALID_CHARS, \"\").slice(0, MAX_LENGTH);\n};\n\ninterface ToSafeCellValueArgs {\n value: CellValue;\n valueType: ColumnMetadata[\"valueType\"];\n}\n\nconst toSafeCellValue = ({ value, valueType }: ToSafeCellValueArgs): CellValue => {\n if (!isNullish(value) && valueType === \"number\") {\n const numValue = typeof value === \"number\" ? value : Number(value);\n return isNaN(numValue) ? value : numValue;\n }\n\n return value ?? \"\";\n};\n\ninterface ToSafeCellValuesArgs {\n headers: string[];\n rowData: Record<string, CellValue>;\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst toSafeCellValues = ({ headers, rowData, columnsMetadata }: ToSafeCellValuesArgs): CellValue[] => {\n return headers.map((header) => {\n const value = rowData[header];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n return toSafeCellValue({ value, valueType });\n });\n};\n\ninterface ApplyTextFormattingArgs {\n row: ExcelJS.Row;\n headers: string[];\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst applyTextFormatting = ({ row, headers, columnsMetadata }: ApplyTextFormattingArgs): void => {\n for (let colIndex = 0; colIndex < headers.length; colIndex++) {\n const header = headers[colIndex];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n\n if (valueType === \"text\") {\n const cell = row.getCell(colIndex + 1);\n cell.numFmt = \"@\";\n }\n }\n};\n\nconst applyHeaderStyles = (headerRow: ExcelJS.Row): void => {\n headerRow.font = { bold: true };\n headerRow.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"FFE0E0E0\" },\n };\n headerRow.alignment = { wrapText: true, vertical: \"top\" };\n};\n\ninterface SetupHeaderFrozenRowArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n}\n\nconst setupHeaderFrozenRow = ({ worksheet, headers }: SetupHeaderFrozenRowArgs): void => {\n const headerRow = worksheet.addRow(headers);\n applyHeaderStyles(headerRow);\n worksheet.views = [{ state: \"frozen\", ySplit: 1 }];\n};\n\ninterface ApplyDataRowStylesArgs {\n worksheet: ExcelJS.Worksheet;\n startRowIndex: number;\n endRowIndex: number;\n}\n\nconst applyDataRowStyles = ({ worksheet, startRowIndex, endRowIndex }: ApplyDataRowStylesArgs): void => {\n for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {\n const row = worksheet.getRow(rowIndex);\n row.alignment = { wrapText: false, vertical: \"top\" };\n }\n};\n\ninterface SetColumnWidthsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nconst setColumnWidths = ({ worksheet, headers, columnsMetadata }: SetColumnWidthsArgs): void => {\n worksheet.columns = headers.map((header) => {\n const metadata = columnsMetadata[header];\n return metadata ? { width: metadata.width } : {};\n });\n};\n\ninterface AddDataRowsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n data: Record<string, CellValue>[];\n}\n\nconst addDataRows = ({ worksheet, headers, columnsMetadata, data }: AddDataRowsArgs): void => {\n for (const rowData of data) {\n const safeCellValues = toSafeCellValues({ headers, rowData, columnsMetadata });\n const row = worksheet.addRow(safeCellValues);\n applyTextFormatting({ row, headers, columnsMetadata });\n }\n\n applyDataRowStyles({ worksheet, startRowIndex: 2, endRowIndex: data.length + 1 });\n};\n\ninterface GenerateExcelBlobArgs {\n worksheetTitle: string;\n data: Record<string, CellValue>[];\n /**\n * Metadata for columns, keyed by column name (translated header name).\n * If not provided, columns will use default width and auto-detect value types.\n */\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nexport const generateExcelBlob = async (args: GenerateExcelBlobArgs): Promise<Blob> => {\n const { data, columnsMetadata, worksheetTitle } = args;\n\n if (data.length === 0) {\n throw new Error(\"No data to export\");\n }\n\n const headers = Object.keys(data[0]);\n const workbook = new ExcelJS.Workbook();\n const worksheet = workbook.addWorksheet(sanitizeWorksheetTitle(worksheetTitle));\n\n setupHeaderFrozenRow({ worksheet, headers });\n addDataRows({ worksheet, headers, columnsMetadata, data });\n setColumnWidths({ worksheet, headers, columnsMetadata });\n\n const buffer = await workbook.xlsx.writeBuffer();\n return new Blob([buffer], { type: getMimeType(\"xlsx\") });\n};\n"]}
package/dist/excel.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/excel/excel-generator.ts","../src/excel/excel-generator.types.ts","../src/utils/types.utils.ts","../src/mime/index.ts","../src/excel/exceljs.utils.ts"],"names":[],"mappings":"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","file":"excel.js","sourcesContent":["import ExcelJS from \"exceljs\";\nimport type { CellStyle, CellValue } from \"./excel-generator.types\";\n\ninterface AddCellArgs {\n row: number;\n col: number;\n value: CellValue;\n style?: CellStyle;\n}\n\ninterface AddRowArgs {\n values: CellValue[];\n styles?: CellStyle[];\n}\n\nexport class WorksheetBuilder {\n private worksheet: ExcelJS.Worksheet;\n private currentRow: number;\n private defaultRowStyles: CellStyle[];\n\n constructor(worksheet: ExcelJS.Worksheet) {\n this.worksheet = worksheet;\n this.currentRow = 1; // ExcelJS uses 1-based indexing\n this.defaultRowStyles = [];\n }\n\n /** Returns the current row index (1-based). */\n get rowCount(): number {\n return this.currentRow;\n }\n\n addCell({ row, col, value, style }: AddCellArgs): void {\n const cell = this.worksheet.getCell(row + 1, col + 1); // Convert to 1-based\n cell.value = value ?? \"\";\n\n if (style) {\n this.applyStyle(cell, style);\n }\n }\n\n addRow({ values, styles }: AddRowArgs): void {\n const stylesToUse = styles ?? this.defaultRowStyles;\n const row = this.worksheet.addRow(values);\n\n // Apply styles to each cell in the row\n for (let col = 0; col < values.length; col++) {\n const style = stylesToUse[col];\n if (style) {\n const cell = row.getCell(col + 1); // ExcelJS uses 1-based indexing\n this.applyStyle(cell, style);\n }\n }\n\n this.currentRow++;\n }\n\n setDefaultRowStyles(styles: CellStyle[]): void {\n this.defaultRowStyles = styles;\n }\n\n addEmptyRow(): void {\n this.worksheet.addRow([]);\n this.currentRow++;\n }\n\n setColumnWidths(columnWidths: number[]): void {\n this.worksheet.columns = columnWidths.map((width) => ({ width }));\n }\n\n getWorksheet(): ExcelJS.Worksheet {\n return this.worksheet;\n }\n\n private applyStyle(cell: ExcelJS.Cell, style: CellStyle): void {\n if (style.font) {\n cell.font = { ...cell.font, ...style.font };\n }\n\n if (style.fill) {\n cell.fill = style.fill as ExcelJS.Fill;\n }\n\n if (style.alignment) {\n cell.alignment = { ...cell.alignment, ...style.alignment };\n }\n\n if (style.border) {\n cell.border = { ...cell.border, ...style.border };\n }\n\n if (style.numFmt) {\n cell.numFmt = style.numFmt;\n }\n }\n}\n","import type { Font, Fill, Alignment } from \"exceljs\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport type VerticalAlignment = \"top\" | \"middle\" | \"bottom\";\nexport type HorizontalAlignment = \"left\" | \"center\" | \"right\";\n\nexport type ColumnValueType = \"number\" | \"text\" | \"auto\";\n\nexport interface ColumnMetadata {\n name: string;\n width: number;\n valueType?: ColumnValueType;\n}\n\ninterface BorderSide {\n style?: \"thin\" | \"medium\" | \"thick\" | \"dotted\" | \"dashed\" | \"double\";\n color?: { argb: string };\n}\n\n/**\n * Type for ExcelJS cell borders.\n */\nexport interface CellBorder {\n top?: BorderSide;\n bottom?: BorderSide;\n left?: BorderSide;\n right?: BorderSide;\n}\n\n/**\n * Type for ExcelJS cell styles.\n * This is a simplified version of ExcelJS.Style that focuses on commonly used properties.\n */\nexport interface CellStyle {\n font?: Partial<Font>;\n fill?: Partial<Fill>;\n alignment?: Partial<Alignment>;\n border?: CellBorder;\n numFmt?: string;\n}\n\n/**\n * Helper type to convert RGB color string to ARGB format for ExcelJS.\n * ExcelJS uses ARGB format: \"FFFFFFFF\" where FF is alpha, then RGB.\n */\nexport type ArgbColor = { argb: string };\n\n/**\n * Helper function to convert RGB color string to ARGB format.\n * @param rgb - RGB color string without # (e.g., \"FFFFFF\")\n * @returns ARGB color object (e.g., { argb: \"FFFFFFFF\" })\n */\nexport const rgbToArgb = (rgb: string): ArgbColor => {\n return { argb: `FF${rgb}` };\n};\n","export const NO_OP: () => void = () => {};\n\nexport const isNullish = (value: unknown): value is null | undefined => value === null || value === undefined;\n\nexport const isNumber = (value?: unknown | null): value is number => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'number') {\n return false;\n }\n\n if (isNaN(value)) {\n return false;\n }\n\n return true;\n};\n\nexport const isString = (value?: unknown | null): value is string => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'string') {\n return false;\n }\n\n return true;\n};\n","import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from \"./mime.utils\";\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import ExcelJS from \"exceljs\";\nimport { getMimeType } from \"../mime\";\nimport { isNullish } from \"../utils\";\nimport type { CellValue, ColumnMetadata } from \"./excel-generator.types\";\n\n/**\n * Sanitizes a worksheet title to comply with Excel's limitations.\n *\n * Excel enforces strict rules for worksheet names:\n * - Maximum length of 31 characters (legacy limitation from older Excel versions)\n * - Certain characters are reserved for special purposes and cannot be used:\n * - `:` (colon) - used in cell range references (e.g., A1:B2)\n * - `/` (forward slash) - used in file paths\n * - `\\` (backslash) - used in file paths and escape sequences\n * - `?` (question mark) - used as wildcard in formulas\n * - `*` (asterisk) - used as wildcard in formulas\n * - `[` and `]` (square brackets) - used in external references (e.g., [Book1.xlsx]Sheet1!A1)\n *\n * This function removes invalid characters and truncates the title to 31 characters\n * to ensure compatibility with Excel's file format specifications.\n *\n * @param title - The original worksheet title to sanitize\n * @returns A sanitized title that complies with Excel's naming rules\n */\nexport const sanitizeWorksheetTitle = (title: string): string => {\n const MAX_LENGTH = 31;\n const INVALID_CHARS = /[:/\\\\?*[\\]]/g;\n\n return title.trim().replace(INVALID_CHARS, \"\").slice(0, MAX_LENGTH);\n};\n\ninterface ToSafeCellValueArgs {\n value: CellValue;\n valueType: ColumnMetadata[\"valueType\"];\n}\n\nconst toSafeCellValue = ({ value, valueType }: ToSafeCellValueArgs): CellValue => {\n if (!isNullish(value) && valueType === \"number\") {\n const numValue = typeof value === \"number\" ? value : Number(value);\n return isNaN(numValue) ? value : numValue;\n }\n\n return value ?? \"\";\n};\n\ninterface ToSafeCellValuesArgs {\n headers: string[];\n rowData: Record<string, CellValue>;\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst toSafeCellValues = ({ headers, rowData, columnsMetadata }: ToSafeCellValuesArgs): CellValue[] => {\n return headers.map((header) => {\n const value = rowData[header];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n return toSafeCellValue({ value, valueType });\n });\n};\n\ninterface ApplyTextFormattingArgs {\n row: ExcelJS.Row;\n headers: string[];\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst applyTextFormatting = ({ row, headers, columnsMetadata }: ApplyTextFormattingArgs): void => {\n for (let colIndex = 0; colIndex < headers.length; colIndex++) {\n const header = headers[colIndex];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n\n if (valueType === \"text\") {\n const cell = row.getCell(colIndex + 1);\n cell.numFmt = \"@\";\n }\n }\n};\n\nconst applyHeaderStyles = (headerRow: ExcelJS.Row): void => {\n headerRow.font = { bold: true };\n headerRow.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"FFE0E0E0\" },\n };\n headerRow.alignment = { wrapText: true, vertical: \"top\" };\n};\n\ninterface SetupHeaderFrozenRowArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n}\n\nconst setupHeaderFrozenRow = ({ worksheet, headers }: SetupHeaderFrozenRowArgs): void => {\n const headerRow = worksheet.addRow(headers);\n applyHeaderStyles(headerRow);\n worksheet.views = [{ state: \"frozen\", ySplit: 1 }];\n};\n\ninterface ApplyDataRowStylesArgs {\n worksheet: ExcelJS.Worksheet;\n startRowIndex: number;\n endRowIndex: number;\n}\n\nconst applyDataRowStyles = ({ worksheet, startRowIndex, endRowIndex }: ApplyDataRowStylesArgs): void => {\n for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {\n const row = worksheet.getRow(rowIndex);\n row.alignment = { wrapText: false, vertical: \"top\" };\n }\n};\n\ninterface SetColumnWidthsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nconst setColumnWidths = ({ worksheet, headers, columnsMetadata }: SetColumnWidthsArgs): void => {\n worksheet.columns = headers.map((header) => {\n const metadata = columnsMetadata[header];\n return metadata ? { width: metadata.width } : {};\n });\n};\n\ninterface AddDataRowsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n data: Record<string, CellValue>[];\n}\n\nconst addDataRows = ({ worksheet, headers, columnsMetadata, data }: AddDataRowsArgs): void => {\n for (const rowData of data) {\n const safeCellValues = toSafeCellValues({ headers, rowData, columnsMetadata });\n const row = worksheet.addRow(safeCellValues);\n applyTextFormatting({ row, headers, columnsMetadata });\n }\n\n applyDataRowStyles({ worksheet, startRowIndex: 2, endRowIndex: data.length + 1 });\n};\n\ninterface GenerateExcelBlobArgs {\n worksheetTitle: string;\n data: Record<string, CellValue>[];\n /**\n * Metadata for columns, keyed by column name (translated header name).\n * If not provided, columns will use default width and auto-detect value types.\n */\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nexport const generateExcelBlob = async (args: GenerateExcelBlobArgs): Promise<Blob> => {\n const { data, columnsMetadata, worksheetTitle } = args;\n\n if (data.length === 0) {\n throw new Error(\"No data to export\");\n }\n\n const headers = Object.keys(data[0]);\n const workbook = new ExcelJS.Workbook();\n const worksheet = workbook.addWorksheet(sanitizeWorksheetTitle(worksheetTitle));\n\n setupHeaderFrozenRow({ worksheet, headers });\n addDataRows({ worksheet, headers, columnsMetadata, data });\n setColumnWidths({ worksheet, headers, columnsMetadata });\n\n const buffer = await workbook.xlsx.writeBuffer();\n return new Blob([buffer], { type: getMimeType(\"xlsx\") });\n};\n"]}
1
+ {"version":3,"sources":["../src/excel/excel-generator.ts","../src/excel/excel-generator.types.ts","../src/utils/types.utils.ts","../src/mime/index.ts","../src/excel/exceljs.utils.ts"],"names":[],"mappings":"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","file":"excel.js","sourcesContent":["import ExcelJS from \"exceljs\";\nimport type { CellStyle, CellValue } from \"./excel-generator.types\";\n\ninterface AddCellArgs {\n row: number;\n col: number;\n value: CellValue;\n style?: CellStyle;\n}\n\ninterface AddRowArgs {\n values: CellValue[];\n styles?: CellStyle[];\n}\n\nexport class WorksheetBuilder {\n private worksheet: ExcelJS.Worksheet;\n private currentRow: number;\n private defaultRowStyles: CellStyle[];\n\n constructor(worksheet: ExcelJS.Worksheet) {\n this.worksheet = worksheet;\n this.currentRow = 1; // ExcelJS uses 1-based indexing\n this.defaultRowStyles = [];\n }\n\n /** Returns the current row index (1-based). */\n get rowCount(): number {\n return this.currentRow;\n }\n\n addCell({ row, col, value, style }: AddCellArgs): void {\n const cell = this.worksheet.getCell(row + 1, col + 1); // Convert to 1-based\n cell.value = value ?? \"\";\n\n if (style) {\n this.applyStyle(cell, style);\n }\n }\n\n addRow({ values, styles }: AddRowArgs): void {\n const stylesToUse = styles ?? this.defaultRowStyles;\n const row = this.worksheet.addRow(values);\n\n // Apply styles to each cell in the row\n for (let col = 0; col < values.length; col++) {\n const style = stylesToUse[col];\n if (style) {\n const cell = row.getCell(col + 1); // ExcelJS uses 1-based indexing\n this.applyStyle(cell, style);\n }\n }\n\n this.currentRow++;\n }\n\n setDefaultRowStyles(styles: CellStyle[]): void {\n this.defaultRowStyles = styles;\n }\n\n addEmptyRow(): void {\n this.worksheet.addRow([]);\n this.currentRow++;\n }\n\n setColumnWidths(columnWidths: number[]): void {\n this.worksheet.columns = columnWidths.map((width) => ({ width }));\n }\n\n getWorksheet(): ExcelJS.Worksheet {\n return this.worksheet;\n }\n\n private applyStyle(cell: ExcelJS.Cell, style: CellStyle): void {\n if (style.font) {\n cell.font = { ...cell.font, ...style.font };\n }\n\n if (style.fill) {\n cell.fill = style.fill as ExcelJS.Fill;\n }\n\n if (style.alignment) {\n cell.alignment = { ...cell.alignment, ...style.alignment };\n }\n\n if (style.border) {\n cell.border = { ...cell.border, ...style.border };\n }\n\n if (style.numFmt) {\n cell.numFmt = style.numFmt;\n }\n }\n}\n","import type { Font, Fill, Alignment } from \"exceljs\";\n\nexport type CellValue = string | number | null | undefined;\n\nexport type VerticalAlignment = \"top\" | \"middle\" | \"bottom\";\nexport type HorizontalAlignment = \"left\" | \"center\" | \"right\";\n\nexport type ColumnValueType = \"number\" | \"text\" | \"auto\";\n\nexport interface ColumnMetadata {\n name: string;\n width: number;\n valueType?: ColumnValueType;\n}\n\ninterface BorderSide {\n style?: \"thin\" | \"medium\" | \"thick\" | \"dotted\" | \"dashed\" | \"double\";\n color?: { argb: string };\n}\n\n/**\n * Type for ExcelJS cell borders.\n */\nexport interface CellBorder {\n top?: BorderSide;\n bottom?: BorderSide;\n left?: BorderSide;\n right?: BorderSide;\n}\n\n/**\n * Type for ExcelJS cell styles.\n * This is a simplified version of ExcelJS.Style that focuses on commonly used properties.\n */\nexport interface CellStyle {\n font?: Partial<Font>;\n fill?: Partial<Fill>;\n alignment?: Partial<Alignment>;\n border?: CellBorder;\n numFmt?: string;\n}\n\n/**\n * Helper type to convert RGB color string to ARGB format for ExcelJS.\n * ExcelJS uses ARGB format: \"FFFFFFFF\" where FF is alpha, then RGB.\n */\nexport type ArgbColor = { argb: string };\n\n/**\n * Helper function to convert RGB color string to ARGB format.\n * @param rgb - RGB color string without # (e.g., \"FFFFFF\")\n * @returns ARGB color object (e.g., { argb: \"FFFFFFFF\" })\n */\nexport const rgbToArgb = (rgb: string): ArgbColor => {\n return { argb: `FF${rgb}` };\n};\n","export const NO_OP: () => void = () => {};\n\nexport const isNullish = (value: unknown): value is null | undefined => value === null || value === undefined;\n\nexport const isNumber = (value?: unknown | null): value is number => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'number') {\n return false;\n }\n\n if (isNaN(value)) {\n return false;\n }\n\n return true;\n};\n\nexport const isString = (value?: unknown | null): value is string => {\n if (isNullish(value)) {\n return false;\n }\n\n if (typeof value !== 'string') {\n return false;\n }\n\n return true;\n};\n","import mime from \"mime\";\n\nimport { DATA_URI_PATTERN, isValidDataUri } from \"~/utils/uri.utils\";\nimport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport { VALID_IMAGE_TYPES } from './mime.utils';\n\nexport interface ParseDataUriResult {\n mimeType: string;\n base64: string;\n ext: string;\n}\n\nexport const parseDataUri = (input: string): ParseDataUriResult | null => {\n if (!isValidDataUri(input)) return null;\n\n const match = DATA_URI_PATTERN.exec(input);\n if (!match) return null;\n\n const [, mimeType, base64] = match;\n if (!mimeType || !base64) return null;\n\n return { mimeType, base64, ext: mimeToExt(mimeType) };\n};\n\nexport const isImageMimeType = (mimeType: string): boolean => {\n return VALID_IMAGE_TYPES.includes(mimeType);\n};\n\nexport const isValidImageFile = (file: { type: string }): boolean => {\n return isImageMimeType(file.type);\n};\n\nexport const getExtensionFromDataUri = (dataUri: string): string => {\n const parsed = parseDataUri(dataUri);\n if (!parsed) return 'bin';\n\n return parsed.ext;\n};\n\nexport const getImagePreviewSrc = (input: string): string | null => {\n const parsed = parseDataUri(input);\n if (!parsed) return null;\n if (!isImageMimeType(parsed.mimeType)) return null;\n\n return input;\n};\n\nexport const mimeToExt = (mimeType: string): string => {\n const ext = mime.getExtension(mimeType);\n if (ext) return ext;\n\n const subtype = mimeType.split(\"/\")[1] ?? mimeType;\n return subtype.split(\"+\")[0] ?? subtype;\n};\n\nexport const getMimeType = (extension: string): string => {\n const mimeType = mime.getType(extension);\n if (!mimeType) {\n throw new Error(`[getMimeType] Mime type not found for extension: \"${extension}\"`);\n }\n\n return mimeType;\n};\n\n","import ExcelJS from \"exceljs\";\nimport { getMimeType } from \"../mime\";\nimport { isNullish } from \"../utils\";\nimport type { CellValue, ColumnMetadata } from \"./excel-generator.types\";\n\n/**\n * Sanitizes a worksheet title to comply with Excel's limitations.\n *\n * Excel enforces strict rules for worksheet names:\n * - Maximum length of 31 characters (legacy limitation from older Excel versions)\n * - Certain characters are reserved for special purposes and cannot be used:\n * - `:` (colon) - used in cell range references (e.g., A1:B2)\n * - `/` (forward slash) - used in file paths\n * - `\\` (backslash) - used in file paths and escape sequences\n * - `?` (question mark) - used as wildcard in formulas\n * - `*` (asterisk) - used as wildcard in formulas\n * - `[` and `]` (square brackets) - used in external references (e.g., [Book1.xlsx]Sheet1!A1)\n *\n * This function removes invalid characters and truncates the title to 31 characters\n * to ensure compatibility with Excel's file format specifications.\n *\n * @param title - The original worksheet title to sanitize\n * @returns A sanitized title that complies with Excel's naming rules\n */\nexport const sanitizeWorksheetTitle = (title: string): string => {\n const MAX_LENGTH = 31;\n const INVALID_CHARS = /[:/\\\\?*[\\]]/g;\n\n return title.trim().replace(INVALID_CHARS, \"\").slice(0, MAX_LENGTH);\n};\n\ninterface ToSafeCellValueArgs {\n value: CellValue;\n valueType: ColumnMetadata[\"valueType\"];\n}\n\nconst toSafeCellValue = ({ value, valueType }: ToSafeCellValueArgs): CellValue => {\n if (!isNullish(value) && valueType === \"number\") {\n const numValue = typeof value === \"number\" ? value : Number(value);\n return isNaN(numValue) ? value : numValue;\n }\n\n return value ?? \"\";\n};\n\ninterface ToSafeCellValuesArgs {\n headers: string[];\n rowData: Record<string, CellValue>;\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst toSafeCellValues = ({ headers, rowData, columnsMetadata }: ToSafeCellValuesArgs): CellValue[] => {\n return headers.map((header) => {\n const value = rowData[header];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n return toSafeCellValue({ value, valueType });\n });\n};\n\ninterface ApplyTextFormattingArgs {\n row: ExcelJS.Row;\n headers: string[];\n columnsMetadata?: Record<string, ColumnMetadata>;\n}\n\nconst applyTextFormatting = ({ row, headers, columnsMetadata }: ApplyTextFormattingArgs): void => {\n for (let colIndex = 0; colIndex < headers.length; colIndex++) {\n const header = headers[colIndex];\n const metadata = columnsMetadata?.[header];\n const valueType = metadata?.valueType ?? \"auto\";\n\n if (valueType === \"text\") {\n const cell = row.getCell(colIndex + 1);\n cell.numFmt = \"@\";\n }\n }\n};\n\nconst applyHeaderStyles = (headerRow: ExcelJS.Row): void => {\n headerRow.font = { bold: true };\n headerRow.fill = {\n type: \"pattern\",\n pattern: \"solid\",\n fgColor: { argb: \"FFE0E0E0\" },\n };\n headerRow.alignment = { wrapText: true, vertical: \"top\" };\n};\n\ninterface SetupHeaderFrozenRowArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n}\n\nconst setupHeaderFrozenRow = ({ worksheet, headers }: SetupHeaderFrozenRowArgs): void => {\n const headerRow = worksheet.addRow(headers);\n applyHeaderStyles(headerRow);\n worksheet.views = [{ state: \"frozen\", ySplit: 1 }];\n};\n\ninterface ApplyDataRowStylesArgs {\n worksheet: ExcelJS.Worksheet;\n startRowIndex: number;\n endRowIndex: number;\n}\n\nconst applyDataRowStyles = ({ worksheet, startRowIndex, endRowIndex }: ApplyDataRowStylesArgs): void => {\n for (let rowIndex = startRowIndex; rowIndex <= endRowIndex; rowIndex++) {\n const row = worksheet.getRow(rowIndex);\n row.alignment = { wrapText: false, vertical: \"top\" };\n }\n};\n\ninterface SetColumnWidthsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nconst setColumnWidths = ({ worksheet, headers, columnsMetadata }: SetColumnWidthsArgs): void => {\n worksheet.columns = headers.map((header) => {\n const metadata = columnsMetadata[header];\n return metadata ? { width: metadata.width } : {};\n });\n};\n\ninterface AddDataRowsArgs {\n worksheet: ExcelJS.Worksheet;\n headers: string[];\n columnsMetadata: Record<string, ColumnMetadata>;\n data: Record<string, CellValue>[];\n}\n\nconst addDataRows = ({ worksheet, headers, columnsMetadata, data }: AddDataRowsArgs): void => {\n for (const rowData of data) {\n const safeCellValues = toSafeCellValues({ headers, rowData, columnsMetadata });\n const row = worksheet.addRow(safeCellValues);\n applyTextFormatting({ row, headers, columnsMetadata });\n }\n\n applyDataRowStyles({ worksheet, startRowIndex: 2, endRowIndex: data.length + 1 });\n};\n\ninterface GenerateExcelBlobArgs {\n worksheetTitle: string;\n data: Record<string, CellValue>[];\n /**\n * Metadata for columns, keyed by column name (translated header name).\n * If not provided, columns will use default width and auto-detect value types.\n */\n columnsMetadata: Record<string, ColumnMetadata>;\n}\n\nexport const generateExcelBlob = async (args: GenerateExcelBlobArgs): Promise<Blob> => {\n const { data, columnsMetadata, worksheetTitle } = args;\n\n if (data.length === 0) {\n throw new Error(\"No data to export\");\n }\n\n const headers = Object.keys(data[0]);\n const workbook = new ExcelJS.Workbook();\n const worksheet = workbook.addWorksheet(sanitizeWorksheetTitle(worksheetTitle));\n\n setupHeaderFrozenRow({ worksheet, headers });\n addDataRows({ worksheet, headers, columnsMetadata, data });\n setColumnWidths({ worksheet, headers, columnsMetadata });\n\n const buffer = await workbook.xlsx.writeBuffer();\n return new Blob([buffer], { type: getMimeType(\"xlsx\") });\n};\n"]}
package/dist/index.cjs CHANGED
@@ -2,6 +2,116 @@
2
2
 
3
3
  var dateFns = require('date-fns');
4
4
 
5
+ // src/utils/base64.utils.ts
6
+ var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7
+ var encodeUtf8ToBytes = (text) => {
8
+ const codePoints = [];
9
+ for (let i = 0; i < text.length; i++) {
10
+ const codeUnit = text.charCodeAt(i);
11
+ if (codeUnit >= 55296 && codeUnit <= 56319 && i + 1 < text.length) {
12
+ const next = text.charCodeAt(i + 1);
13
+ if (next >= 56320 && next <= 57343) {
14
+ codePoints.push(65536 + (codeUnit - 55296 << 10) + (next - 56320));
15
+ i++;
16
+ continue;
17
+ }
18
+ }
19
+ codePoints.push(codeUnit);
20
+ }
21
+ const bytes = [];
22
+ for (const codePoint of codePoints) {
23
+ if (codePoint < 128) {
24
+ bytes.push(codePoint);
25
+ } else if (codePoint < 2048) {
26
+ bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
27
+ } else if (codePoint < 65536) {
28
+ bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
29
+ } else {
30
+ bytes.push(
31
+ 240 | codePoint >> 18,
32
+ 128 | codePoint >> 12 & 63,
33
+ 128 | codePoint >> 6 & 63,
34
+ 128 | codePoint & 63
35
+ );
36
+ }
37
+ }
38
+ return bytes;
39
+ };
40
+ var decodeUtf8FromBytes = (bytes) => {
41
+ let result = "";
42
+ let i = 0;
43
+ while (i < bytes.length) {
44
+ const b0 = bytes[i];
45
+ let codePoint;
46
+ if (b0 < 128) {
47
+ codePoint = b0;
48
+ i += 1;
49
+ } else if ((b0 & 224) === 192) {
50
+ codePoint = (b0 & 31) << 6 | bytes[i + 1] & 63;
51
+ i += 2;
52
+ } else if ((b0 & 240) === 224) {
53
+ codePoint = (b0 & 15) << 12 | (bytes[i + 1] & 63) << 6 | bytes[i + 2] & 63;
54
+ i += 3;
55
+ } else {
56
+ codePoint = (b0 & 7) << 18 | (bytes[i + 1] & 63) << 12 | (bytes[i + 2] & 63) << 6 | bytes[i + 3] & 63;
57
+ i += 4;
58
+ }
59
+ if (codePoint <= 65535) {
60
+ result += String.fromCharCode(codePoint);
61
+ } else {
62
+ const adjusted = codePoint - 65536;
63
+ result += String.fromCharCode(55296 + (adjusted >> 10), 56320 + (adjusted & 1023));
64
+ }
65
+ }
66
+ return result;
67
+ };
68
+ var encodeBytesToBase64 = (bytes) => {
69
+ let output = "";
70
+ for (let i = 0; i < bytes.length; i += 3) {
71
+ const b0 = bytes[i];
72
+ const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
73
+ const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
74
+ const triplet = b0 << 16 | b1 << 8 | b2;
75
+ output += BASE64_CHARS[triplet >> 18 & 63];
76
+ output += BASE64_CHARS[triplet >> 12 & 63];
77
+ output += i + 1 < bytes.length ? BASE64_CHARS[triplet >> 6 & 63] : "=";
78
+ output += i + 2 < bytes.length ? BASE64_CHARS[triplet & 63] : "=";
79
+ }
80
+ return output;
81
+ };
82
+ var decodeBase64ToBytes = (base64) => {
83
+ const sanitized = base64.replace(/[^A-Za-z0-9+/=]/g, "");
84
+ const bytes = [];
85
+ for (let i = 0; i < sanitized.length; i += 4) {
86
+ const c0 = BASE64_CHARS.indexOf(sanitized[i]);
87
+ const c1 = BASE64_CHARS.indexOf(sanitized[i + 1]);
88
+ const c2 = sanitized[i + 2] === "=" ? 0 : BASE64_CHARS.indexOf(sanitized[i + 2]);
89
+ const c3 = sanitized[i + 3] === "=" ? 0 : BASE64_CHARS.indexOf(sanitized[i + 3]);
90
+ if (c0 < 0 || c1 < 0 || sanitized[i + 2] !== "=" && c2 < 0 || sanitized[i + 3] !== "=" && c3 < 0) {
91
+ throw new Error("Invalid base64 character");
92
+ }
93
+ const triplet = c0 << 18 | c1 << 12 | c2 << 6 | c3;
94
+ bytes.push(triplet >> 16 & 255);
95
+ if (sanitized[i + 2] !== "=") bytes.push(triplet >> 8 & 255);
96
+ if (sanitized[i + 3] !== "=") bytes.push(triplet & 255);
97
+ }
98
+ return bytes;
99
+ };
100
+ var encodeBase64 = (text) => {
101
+ try {
102
+ return encodeBytesToBase64(encodeUtf8ToBytes(text));
103
+ } catch {
104
+ return "";
105
+ }
106
+ };
107
+ var decodeBase64 = (base64) => {
108
+ try {
109
+ return decodeUtf8FromBytes(decodeBase64ToBytes(base64));
110
+ } catch {
111
+ return "";
112
+ }
113
+ };
114
+
5
115
  // src/utils/types.utils.ts
6
116
  var NO_OP = () => {
7
117
  };
@@ -284,6 +394,29 @@ var toFormStringInteger = (n) => {
284
394
  return String(Math.round(n));
285
395
  };
286
396
 
397
+ // src/utils/html.utils.ts
398
+ var HTML_ESCAPE_MAP = {
399
+ "&": "&amp;",
400
+ "<": "&lt;",
401
+ ">": "&gt;",
402
+ '"': "&quot;",
403
+ "'": "&#39;"
404
+ };
405
+ var HTML_UNESCAPE_MAP = {
406
+ "&amp;": "&",
407
+ "&lt;": "<",
408
+ "&gt;": ">",
409
+ "&quot;": '"',
410
+ "&#39;": "'",
411
+ "&#x27;": "'"
412
+ };
413
+ var escapeHtml = (text) => {
414
+ return text.replace(/[&<>"']/g, (char) => HTML_ESCAPE_MAP[char] ?? char);
415
+ };
416
+ var unescapeHtml = (text) => {
417
+ return text.replace(/&(?:amp|lt|gt|quot|#39|#x27);/g, (entity) => HTML_UNESCAPE_MAP[entity] ?? entity);
418
+ };
419
+
287
420
  // src/utils/http.utils.ts
288
421
  var isHttpSuccessStatus = (status) => {
289
422
  if (isNullish(status)) {
@@ -304,6 +437,56 @@ var isHttpServerErrorStatus = (status) => {
304
437
  return status >= 500;
305
438
  };
306
439
 
440
+ // src/utils/json.utils.ts
441
+ var safeJsonParse = (value, fallback) => {
442
+ try {
443
+ return JSON.parse(value);
444
+ } catch {
445
+ return fallback;
446
+ }
447
+ };
448
+ var safeJsonStringify = (obj, space = 2) => {
449
+ if (!obj) return "";
450
+ try {
451
+ return JSON.stringify(obj, null, space);
452
+ } catch {
453
+ return "";
454
+ }
455
+ };
456
+ var sortObjectKeys = (_key, value) => value instanceof Object && !(value instanceof Array) ? Object.keys(value).sort().reduce(
457
+ (sorted, key) => {
458
+ sorted[key] = value[key];
459
+ return sorted;
460
+ },
461
+ {}
462
+ ) : value;
463
+ var formatJson = ({ value, space = 2, sortKeys = false }) => {
464
+ if (!value) return "";
465
+ try {
466
+ const obj = JSON.parse(value);
467
+ return JSON.stringify(obj, sortKeys ? sortObjectKeys : void 0, space);
468
+ } catch {
469
+ return value;
470
+ }
471
+ };
472
+ var prettifyJson = (value) => {
473
+ return formatJson({ value, space: 4, sortKeys: true });
474
+ };
475
+ var minifyJson = (value) => {
476
+ return formatJson({ value, space: 0, sortKeys: true });
477
+ };
478
+ var isValidJson = (value) => {
479
+ try {
480
+ JSON.parse(value);
481
+ return true;
482
+ } catch {
483
+ return false;
484
+ }
485
+ };
486
+ var isMinifiedJson = (value) => {
487
+ return value === minifyJson(value);
488
+ };
489
+
307
490
  // src/utils/number.utils.ts
308
491
  var isInputValidNumber = (value) => {
309
492
  if (isBlank(value)) return false;
@@ -337,6 +520,21 @@ var roundUpToNearest10 = (value) => {
337
520
  if (isNullish(value)) return 0;
338
521
  return Math.ceil(value / 10) * 10;
339
522
  };
523
+ var formatCount = (count) => {
524
+ if (count >= 1e6) {
525
+ return `${(count / 1e6).toFixed(1)}M`;
526
+ }
527
+ if (count >= 1e3) {
528
+ return `${(count / 1e3).toFixed(1)}K`;
529
+ }
530
+ return count.toString();
531
+ };
532
+ var formatDuration = (ms) => {
533
+ if (ms < 1e3) {
534
+ return `${ms}ms`;
535
+ }
536
+ return `${(ms / 1e3).toFixed(1)}s`;
537
+ };
340
538
  var getOrderOfMagnitudeExponent = (n) => {
341
539
  if (isNullish(n)) return 0;
342
540
  if (!isNumber(n)) return 0;
@@ -428,6 +626,24 @@ var hasScheme = (uri) => {
428
626
  var extractBase64FromDataUri = (dataUri) => {
429
627
  return dataUri.split(",")[1] ?? dataUri;
430
628
  };
629
+ var encodeUrl = (value) => {
630
+ if (!value) return "";
631
+ return encodeURIComponent(value);
632
+ };
633
+ var decodeUrl = (value) => {
634
+ if (!value) return "";
635
+ try {
636
+ return decodeURIComponent(value);
637
+ } catch {
638
+ return value;
639
+ }
640
+ };
641
+ var formatDataUri = ({ mimeType, base64 }) => {
642
+ return `data:${mimeType};base64,${base64}`;
643
+ };
644
+ var getBase64ApproxSize = (base64) => {
645
+ return Math.round(base64.length * 3 / 4);
646
+ };
431
647
 
432
648
  // src/utils/websocket.utils.ts
433
649
  var WEBSOCKET_CONNECT_STATES = [WebSocket.CONNECTING, WebSocket.OPEN];
@@ -465,14 +681,24 @@ exports.countWords = countWords;
465
681
  exports.dateAs_HHMMSS = dateAs_HHMMSS;
466
682
  exports.dateAs_YYYYMMDD = dateAs_YYYYMMDD;
467
683
  exports.dateAs_YYYYMMDD_HHMMSS = dateAs_YYYYMMDD_HHMMSS;
684
+ exports.decodeBase64 = decodeBase64;
685
+ exports.decodeUrl = decodeUrl;
686
+ exports.encodeBase64 = encodeBase64;
687
+ exports.encodeUrl = encodeUrl;
688
+ exports.escapeHtml = escapeHtml;
468
689
  exports.extractBase64FromDataUri = extractBase64FromDataUri;
690
+ exports.formatCount = formatCount;
691
+ exports.formatDataUri = formatDataUri;
692
+ exports.formatDuration = formatDuration;
469
693
  exports.formatIntegerDisplay = formatIntegerDisplay;
694
+ exports.formatJson = formatJson;
470
695
  exports.formatUnixTimestamp = formatUnixTimestamp;
471
696
  exports.fromHzToRpm = fromHzToRpm;
472
697
  exports.fromM3psToGPM = fromM3psToGPM;
473
698
  exports.fromMToInches = fromMToInches;
474
699
  exports.fromPaToFt = fromPaToFt;
475
700
  exports.fromWToHp = fromWToHp;
701
+ exports.getBase64ApproxSize = getBase64ApproxSize;
476
702
  exports.getColorForPercentage = getColorForPercentage;
477
703
  exports.getContrastTextColor = getContrastTextColor;
478
704
  exports.getCurrentUnixTimestamp = getCurrentUnixTimestamp;
@@ -497,20 +723,24 @@ exports.isInputValidNegativeInteger = isInputValidNegativeInteger;
497
723
  exports.isInputValidNumber = isInputValidNumber;
498
724
  exports.isInputValidPositiveInteger = isInputValidPositiveInteger;
499
725
  exports.isLightColor = isLightColor;
726
+ exports.isMinifiedJson = isMinifiedJson;
500
727
  exports.isNotBlank = isNotBlank;
501
728
  exports.isNullish = isNullish;
502
729
  exports.isNumber = isNumber;
503
730
  exports.isRuntimeEnvNodeJs = isRuntimeEnvNodeJs;
504
731
  exports.isString = isString;
505
732
  exports.isValidDataUri = isValidDataUri;
733
+ exports.isValidJson = isValidJson;
506
734
  exports.isWsClosable = isWsClosable;
507
735
  exports.isWsOpenOrConnecting = isWsOpenOrConnecting;
736
+ exports.minifyJson = minifyJson;
508
737
  exports.nowAsDate = nowAsDate;
509
738
  exports.nowAsDateTime = nowAsDateTime;
510
739
  exports.nowAsDateTimeForFilename = nowAsDateTimeForFilename;
511
740
  exports.nowAsTime = nowAsTime;
512
741
  exports.parseCommaSeparatedList = parseCommaSeparatedList;
513
742
  exports.parseOptionalFormNumber = parseOptionalFormNumber;
743
+ exports.prettifyJson = prettifyJson;
514
744
  exports.removeDiacriticalMarks = removeDiacriticalMarks;
515
745
  exports.rgbToHex = rgbToHex;
516
746
  exports.rgbToString = rgbToString;
@@ -519,7 +749,10 @@ exports.rgbaToHexWithAlpha = rgbaToHexWithAlpha;
519
749
  exports.rgbaToString = rgbaToString;
520
750
  exports.roundToNiceNumber = roundToNiceNumber;
521
751
  exports.roundUpToNearest10 = roundUpToNearest10;
752
+ exports.safeJsonParse = safeJsonParse;
753
+ exports.safeJsonStringify = safeJsonStringify;
522
754
  exports.sleep = sleep;
755
+ exports.sortObjectKeys = sortObjectKeys;
523
756
  exports.tickFormatter = tickFormatter;
524
757
  exports.toError = toError;
525
758
  exports.toFixed = toFixed;
@@ -528,6 +761,7 @@ exports.toFormStringInteger = toFormStringInteger;
528
761
  exports.toToleranceLabel = toToleranceLabel;
529
762
  exports.tooltipValueFormatter = tooltipValueFormatter;
530
763
  exports.truncate = truncate;
764
+ exports.unescapeHtml = unescapeHtml;
531
765
  exports.yieldToMainThread = yieldToMainThread;
532
766
  //# sourceMappingURL=index.cjs.map
533
767
  //# sourceMappingURL=index.cjs.map