@tmlmobilidade/files 20251202.1817.5
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/files.d.ts +64 -0
- package/dist/files.js +153 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/utils.d.ts +20 -0
- package/dist/utils.js +47 -0
- package/package.json +50 -0
package/dist/files.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import JSZip from 'jszip';
|
|
2
|
+
import { ParseConfig } from 'papaparse';
|
|
3
|
+
interface UpdateCsvFieldParams {
|
|
4
|
+
column: string;
|
|
5
|
+
csvString: string;
|
|
6
|
+
rowIndex: number;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class Files {
|
|
10
|
+
/**
|
|
11
|
+
* Blob to JS File
|
|
12
|
+
*/
|
|
13
|
+
static blobToFile(blob: Blob, fileName: string): File;
|
|
14
|
+
static getFileExtension(fileName: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Gets the file extension from a MIME type.
|
|
17
|
+
* @param mimeType The MIME type to get the file extension for.
|
|
18
|
+
* @returns The file extension, or an empty string if not found.
|
|
19
|
+
*/
|
|
20
|
+
static getFileExtensionFromMimeType(mimeType: string): string;
|
|
21
|
+
static getMimeTypeFromFileExtension(fileName: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Parses a CSV string into an array of objects using PapaParse.
|
|
24
|
+
* @param csvString - The CSV string to parse
|
|
25
|
+
* @param options - Parse configuration options
|
|
26
|
+
* @param options.header - Whether to interpret first row as field names. Defaults to true.
|
|
27
|
+
* @param options.skipEmptyLines - Whether to skip empty lines in the CSV. Defaults to true.
|
|
28
|
+
* @param options.rest - Additional PapaParse configuration options
|
|
29
|
+
* @returns Promise resolving to array of parsed objects
|
|
30
|
+
* @throws Error if parsing fails with details of parsing errors
|
|
31
|
+
*/
|
|
32
|
+
static parseCsv<T>(csvString: string, { header, skipEmptyLines, ...options }: ParseConfig<T>): Promise<T[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Reads and extracts a single file from a ZIP archive.
|
|
35
|
+
* @param zipFilePath - The ZIP file to read from, can be a File object (browser), string path (Node.js), or URL
|
|
36
|
+
* @param fileName - The name of the file to extract from the ZIP
|
|
37
|
+
* @param encoding - The encoding to use when reading the file. See JSZip documentation for supported formats.
|
|
38
|
+
* @returns A Promise resolving to the file contents in the specified encoding
|
|
39
|
+
* @throws Error if the file is not found in the ZIP
|
|
40
|
+
*/
|
|
41
|
+
static readFileFromZip<T extends Parameters<JSZip.JSZipObject['async']>[0]>(zipFilePath: File | string | URL, fileName: string, encoding: T): Promise<ReturnType<JSZip.JSZipObject['async']> extends Promise<infer R> ? R : never>;
|
|
42
|
+
/**
|
|
43
|
+
* Unzips a ZIP file from a File (browser), string path (Node.js), or URL.
|
|
44
|
+
* @param zipFilePath The path, URL, or File object representing the ZIP file to extract.
|
|
45
|
+
* @returns A Promise that resolves to a JSZip instance representing the unzipped contents.
|
|
46
|
+
*/
|
|
47
|
+
static unzip(zipFilePath: File | string | URL): Promise<JSZip>;
|
|
48
|
+
/**
|
|
49
|
+
* Updates a CSV string with an object.
|
|
50
|
+
* @param csvString - The CSV string to update
|
|
51
|
+
* @param column - The column name to update
|
|
52
|
+
* @param row - The row index to update
|
|
53
|
+
* @param value - The value to update the column with
|
|
54
|
+
* @returns A Promise resolving to the updated CSV string
|
|
55
|
+
*/
|
|
56
|
+
static updateCsvField<T>(params: UpdateCsvFieldParams[]): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Zips multiple files into a ZIP archive.
|
|
59
|
+
* @param files An object where keys are filenames and values are either File (browser) or Buffer/Uint8Array (Node.js).
|
|
60
|
+
* @returns A Promise resolving to a Uint8Array representing the ZIP file content.
|
|
61
|
+
*/
|
|
62
|
+
static zip(files: Record<string, Buffer | File | Uint8Array>): Promise<Uint8Array>;
|
|
63
|
+
}
|
|
64
|
+
export {};
|
package/dist/files.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-extraneous-class */
|
|
2
|
+
/* * */
|
|
3
|
+
import { fetchZipFromUrl, isBrowser, normalizeFileContent, readZipFromFile } from './utils.js';
|
|
4
|
+
import { mimeTypes } from '@tmlmobilidade/consts';
|
|
5
|
+
import JSZip from 'jszip';
|
|
6
|
+
import papaparse from 'papaparse';
|
|
7
|
+
/* * */
|
|
8
|
+
export class Files {
|
|
9
|
+
//
|
|
10
|
+
/**
|
|
11
|
+
* Blob to JS File
|
|
12
|
+
*/
|
|
13
|
+
static blobToFile(blob, fileName) {
|
|
14
|
+
return new File([blob], fileName);
|
|
15
|
+
}
|
|
16
|
+
static getFileExtension(fileName) {
|
|
17
|
+
const extension = fileName.split('.').pop();
|
|
18
|
+
if (!extension) {
|
|
19
|
+
throw new Error('File has no extension');
|
|
20
|
+
}
|
|
21
|
+
const mimeType = mimeTypes[extension];
|
|
22
|
+
if (!mimeType) {
|
|
23
|
+
throw new Error(`Unsupported file extension: ${extension}`);
|
|
24
|
+
}
|
|
25
|
+
return extension;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Gets the file extension from a MIME type.
|
|
29
|
+
* @param mimeType The MIME type to get the file extension for.
|
|
30
|
+
* @returns The file extension, or an empty string if not found.
|
|
31
|
+
*/
|
|
32
|
+
static getFileExtensionFromMimeType(mimeType) {
|
|
33
|
+
if (!mimeType)
|
|
34
|
+
return '';
|
|
35
|
+
const extension = Object.keys(mimeTypes).find(key => mimeTypes[key] === mimeType);
|
|
36
|
+
if (!extension)
|
|
37
|
+
return '';
|
|
38
|
+
return extension;
|
|
39
|
+
}
|
|
40
|
+
static getMimeTypeFromFileExtension(fileName) {
|
|
41
|
+
const extension = Files.getFileExtension(fileName);
|
|
42
|
+
return mimeTypes[extension];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parses a CSV string into an array of objects using PapaParse.
|
|
46
|
+
* @param csvString - The CSV string to parse
|
|
47
|
+
* @param options - Parse configuration options
|
|
48
|
+
* @param options.header - Whether to interpret first row as field names. Defaults to true.
|
|
49
|
+
* @param options.skipEmptyLines - Whether to skip empty lines in the CSV. Defaults to true.
|
|
50
|
+
* @param options.rest - Additional PapaParse configuration options
|
|
51
|
+
* @returns Promise resolving to array of parsed objects
|
|
52
|
+
* @throws Error if parsing fails with details of parsing errors
|
|
53
|
+
*/
|
|
54
|
+
static async parseCsv(csvString, { header = true, skipEmptyLines = true, ...options }) {
|
|
55
|
+
const parse = papaparse.parse(csvString, { header, skipEmptyLines, ...options });
|
|
56
|
+
if (parse.errors.length > 0) {
|
|
57
|
+
throw new Error(`Failed to parse CSV: ${parse.errors.map(error => `${error.message} [${error.code}]`).join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
return parse.data;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Reads and extracts a single file from a ZIP archive.
|
|
63
|
+
* @param zipFilePath - The ZIP file to read from, can be a File object (browser), string path (Node.js), or URL
|
|
64
|
+
* @param fileName - The name of the file to extract from the ZIP
|
|
65
|
+
* @param encoding - The encoding to use when reading the file. See JSZip documentation for supported formats.
|
|
66
|
+
* @returns A Promise resolving to the file contents in the specified encoding
|
|
67
|
+
* @throws Error if the file is not found in the ZIP
|
|
68
|
+
*/
|
|
69
|
+
static async readFileFromZip(zipFilePath, fileName, encoding) {
|
|
70
|
+
const zip = await Files.unzip(zipFilePath);
|
|
71
|
+
const file = zip.file(fileName);
|
|
72
|
+
if (!file) {
|
|
73
|
+
throw new Error(`File ${fileName} not found in ZIP`);
|
|
74
|
+
}
|
|
75
|
+
return await file.async(encoding);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Unzips a ZIP file from a File (browser), string path (Node.js), or URL.
|
|
79
|
+
* @param zipFilePath The path, URL, or File object representing the ZIP file to extract.
|
|
80
|
+
* @returns A Promise that resolves to a JSZip instance representing the unzipped contents.
|
|
81
|
+
*/
|
|
82
|
+
static async unzip(zipFilePath) {
|
|
83
|
+
try {
|
|
84
|
+
let data = null;
|
|
85
|
+
if (isBrowser && zipFilePath instanceof File) {
|
|
86
|
+
data = await zipFilePath.arrayBuffer();
|
|
87
|
+
}
|
|
88
|
+
if (typeof zipFilePath === 'string' || zipFilePath instanceof URL) {
|
|
89
|
+
const pathOrUrl = zipFilePath.toString();
|
|
90
|
+
if (isBrowser || pathOrUrl.startsWith('http')) {
|
|
91
|
+
data = await fetchZipFromUrl(pathOrUrl);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
data = await readZipFromFile(pathOrUrl);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!data || data.byteLength === 0) {
|
|
98
|
+
throw new Error('ZIP file is empty');
|
|
99
|
+
}
|
|
100
|
+
const zip = await JSZip.loadAsync(data);
|
|
101
|
+
if (Object.keys(zip.files).length === 0) {
|
|
102
|
+
throw new Error('ZIP file contains no files');
|
|
103
|
+
}
|
|
104
|
+
return zip;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (error instanceof Error && error.message.includes('Central Directory')) {
|
|
108
|
+
throw new Error('Invalid or corrupted ZIP file');
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Updates a CSV string with an object.
|
|
115
|
+
* @param csvString - The CSV string to update
|
|
116
|
+
* @param column - The column name to update
|
|
117
|
+
* @param row - The row index to update
|
|
118
|
+
* @param value - The value to update the column with
|
|
119
|
+
* @returns A Promise resolving to the updated CSV string
|
|
120
|
+
*/
|
|
121
|
+
static async updateCsvField(params) {
|
|
122
|
+
let csv = params[0].csvString;
|
|
123
|
+
for (const param of params) {
|
|
124
|
+
const { column, rowIndex, value } = param;
|
|
125
|
+
const data = await this.parseCsv(csv, { header: true });
|
|
126
|
+
const updatedData = data.map((row, index) => (index === rowIndex ? { ...row, [column]: value } : row));
|
|
127
|
+
csv = papaparse.unparse(updatedData, { header: true });
|
|
128
|
+
}
|
|
129
|
+
return csv;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Zips multiple files into a ZIP archive.
|
|
133
|
+
* @param files An object where keys are filenames and values are either File (browser) or Buffer/Uint8Array (Node.js).
|
|
134
|
+
* @returns A Promise resolving to a Uint8Array representing the ZIP file content.
|
|
135
|
+
*/
|
|
136
|
+
static async zip(files) {
|
|
137
|
+
try {
|
|
138
|
+
const zip = new JSZip();
|
|
139
|
+
await Promise.all(Object.entries(files).map(async ([filename, content]) => {
|
|
140
|
+
const fileData = await normalizeFileContent(content);
|
|
141
|
+
zip.file(filename, fileData);
|
|
142
|
+
}));
|
|
143
|
+
const zipContent = await zip.generateAsync({ type: 'uint8array' });
|
|
144
|
+
if (!zipContent || zipContent.length === 0) {
|
|
145
|
+
throw new Error('Failed to generate ZIP: output is empty');
|
|
146
|
+
}
|
|
147
|
+
return zipContent;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw new Error(`Failed to create ZIP archive: ${error.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const isBrowser: boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Fetches a ZIP file from a URL and returns it as an ArrayBuffer.
|
|
4
|
+
* @param url The URL of the ZIP file to fetch
|
|
5
|
+
* @returns A Promise that resolves to an ArrayBuffer containing the ZIP file data
|
|
6
|
+
* @throws {Error} If the HTTP request fails or returns a non-200 status code
|
|
7
|
+
*/
|
|
8
|
+
export declare function fetchZipFromUrl(url: string): Promise<ArrayBuffer>;
|
|
9
|
+
/**
|
|
10
|
+
* Reads a ZIP file from the local filesystem and returns it as an ArrayBuffer.
|
|
11
|
+
* @param path The file system path to the ZIP file
|
|
12
|
+
* @returns A Promise that resolves to an ArrayBuffer containing the ZIP file data
|
|
13
|
+
* @throws {Error} If there is an error reading the file
|
|
14
|
+
*/
|
|
15
|
+
export declare function readZipFromFile(path: string): Promise<ArrayBuffer>;
|
|
16
|
+
/**
|
|
17
|
+
* Converts the input file data into an ArrayBuffer or Uint8Array suitable for JSZip.
|
|
18
|
+
* @param content A File (browser) or Buffer/Uint8Array (Node.js)
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeFileContent(content: Buffer | File | Uint8Array): Promise<ArrayBuffer | Uint8Array>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|
2
|
+
/**
|
|
3
|
+
* Fetches a ZIP file from a URL and returns it as an ArrayBuffer.
|
|
4
|
+
* @param url The URL of the ZIP file to fetch
|
|
5
|
+
* @returns A Promise that resolves to an ArrayBuffer containing the ZIP file data
|
|
6
|
+
* @throws {Error} If the HTTP request fails or returns a non-200 status code
|
|
7
|
+
*/
|
|
8
|
+
export async function fetchZipFromUrl(url) {
|
|
9
|
+
const response = await fetch(url);
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw new Error(`Failed to fetch ZIP file: HTTP ${response.status} - ${response.statusText}`);
|
|
12
|
+
}
|
|
13
|
+
return await response.arrayBuffer();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Reads a ZIP file from the local filesystem and returns it as an ArrayBuffer.
|
|
17
|
+
* @param path The file system path to the ZIP file
|
|
18
|
+
* @returns A Promise that resolves to an ArrayBuffer containing the ZIP file data
|
|
19
|
+
* @throws {Error} If there is an error reading the file
|
|
20
|
+
*/
|
|
21
|
+
export async function readZipFromFile(path) {
|
|
22
|
+
if (isBrowser) {
|
|
23
|
+
throw new Error('readZipFromFile is not supported in the browser');
|
|
24
|
+
}
|
|
25
|
+
// Only require fs/promises in Node.js
|
|
26
|
+
const { readFile } = await (Function('return import("fs/promises")')());
|
|
27
|
+
try {
|
|
28
|
+
const buffer = await readFile(path);
|
|
29
|
+
return buffer.buffer;
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
throw new Error(`Failed to read ZIP file: ${err.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Converts the input file data into an ArrayBuffer or Uint8Array suitable for JSZip.
|
|
37
|
+
* @param content A File (browser) or Buffer/Uint8Array (Node.js)
|
|
38
|
+
*/
|
|
39
|
+
export async function normalizeFileContent(content) {
|
|
40
|
+
if (isBrowser && content instanceof File) {
|
|
41
|
+
return await content.arrayBuffer();
|
|
42
|
+
}
|
|
43
|
+
if (content instanceof Buffer || content instanceof Uint8Array) {
|
|
44
|
+
return content;
|
|
45
|
+
}
|
|
46
|
+
throw new TypeError('Unsupported file content type for zipping');
|
|
47
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmlmobilidade/files",
|
|
3
|
+
"version": "20251202.1817.5",
|
|
4
|
+
"author": {
|
|
5
|
+
"email": "iso@tmlmobilidade.pt",
|
|
6
|
+
"name": "TML-ISO"
|
|
7
|
+
},
|
|
8
|
+
"license": "AGPL-3.0-or-later",
|
|
9
|
+
"homepage": "https://github.com/tmlmobilidade/go#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/tmlmobilidade/go/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/tmlmobilidade/go.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"public transit",
|
|
19
|
+
"tml",
|
|
20
|
+
"transportes metropolitanos de lisboa",
|
|
21
|
+
"go"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && resolve-tspaths",
|
|
34
|
+
"lint": "eslint ./src/ && tsc --noEmit",
|
|
35
|
+
"lint:fix": "eslint ./src/ --fix",
|
|
36
|
+
"watch": "tsc-watch --onSuccess 'resolve-tspaths'"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@tmlmobilidade/consts": "*",
|
|
40
|
+
"jszip": "3.10.1",
|
|
41
|
+
"papaparse": "5.5.3"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@tmlmobilidade/tsconfig": "*",
|
|
45
|
+
"@types/node": "24.10.1",
|
|
46
|
+
"resolve-tspaths": "0.8.23",
|
|
47
|
+
"tsc-watch": "7.2.0",
|
|
48
|
+
"typescript": "5.9.3"
|
|
49
|
+
}
|
|
50
|
+
}
|