@lumeweb/pinner 0.0.1 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +707 -28
- package/dist/cjs/_virtual/rolldown_runtime.cjs +29 -0
- package/dist/cjs/adapters/pinata/index.cjs +6 -0
- package/dist/cjs/adapters/pinata/legacy/adapter.cjs +83 -0
- package/dist/cjs/adapters/pinata/legacy/adapter.cjs.map +1 -0
- package/dist/cjs/adapters/pinata/legacy/adapter.d.cts +74 -0
- package/dist/cjs/adapters/pinata/legacy/index.cjs +1 -0
- package/dist/cjs/adapters/pinata/shared/index.cjs +1 -0
- package/dist/cjs/adapters/pinata/shared/types.d.cts +218 -0
- package/dist/cjs/adapters/pinata/shared/utils.cjs +83 -0
- package/dist/cjs/adapters/pinata/shared/utils.cjs.map +1 -0
- package/dist/cjs/adapters/pinata/v2/adapter-interface.d.cts +198 -0
- package/dist/cjs/adapters/pinata/v2/adapter.cjs +636 -0
- package/dist/cjs/adapters/pinata/v2/adapter.cjs.map +1 -0
- package/dist/cjs/adapters/pinata/v2/adapter.d.cts +17 -0
- package/dist/cjs/adapters/pinata/v2/index.cjs +1 -0
- package/dist/cjs/adapters/pinata/v2/types.d.cts +308 -0
- package/dist/cjs/blockstore/index.cjs +2 -0
- package/dist/cjs/blockstore/unstorage-base.cjs +240 -0
- package/dist/cjs/blockstore/unstorage-base.cjs.map +1 -0
- package/dist/cjs/blockstore/unstorage-base.d.cts +23 -0
- package/dist/cjs/blockstore/unstorage.cjs +39 -0
- package/dist/cjs/blockstore/unstorage.cjs.map +1 -0
- package/dist/cjs/blockstore/unstorage.d.cts +36 -0
- package/dist/cjs/config.d.cts +51 -0
- package/dist/cjs/encoder/base64.cjs +38 -0
- package/dist/cjs/encoder/base64.cjs.map +1 -0
- package/dist/cjs/encoder/csv/csv-formatter.cjs +81 -0
- package/dist/cjs/encoder/csv/csv-formatter.cjs.map +1 -0
- package/dist/cjs/encoder/csv/field-formatter.cjs +76 -0
- package/dist/cjs/encoder/csv/field-formatter.cjs.map +1 -0
- package/dist/cjs/encoder/csv/row-formatter.cjs +159 -0
- package/dist/cjs/encoder/csv/row-formatter.cjs.map +1 -0
- package/dist/cjs/encoder/csv.cjs +44 -0
- package/dist/cjs/encoder/csv.cjs.map +1 -0
- package/dist/cjs/encoder/error.cjs +19 -0
- package/dist/cjs/encoder/error.cjs.map +1 -0
- package/dist/cjs/encoder/index.cjs +6 -0
- package/dist/cjs/encoder/json.cjs +36 -0
- package/dist/cjs/encoder/json.cjs.map +1 -0
- package/dist/cjs/encoder/text.cjs +35 -0
- package/dist/cjs/encoder/text.cjs.map +1 -0
- package/dist/cjs/encoder/url.cjs +39 -0
- package/dist/cjs/encoder/url.cjs.map +1 -0
- package/dist/cjs/errors/index.cjs +104 -0
- package/dist/cjs/errors/index.cjs.map +1 -0
- package/dist/cjs/errors/index.d.cts +47 -0
- package/dist/cjs/index.cjs +44 -0
- package/dist/cjs/index.d.cts +16 -0
- package/dist/cjs/pin/client.cjs +98 -0
- package/dist/cjs/pin/client.cjs.map +1 -0
- package/dist/cjs/pin/index.cjs +1 -0
- package/dist/cjs/pinner.cjs +132 -0
- package/dist/cjs/pinner.cjs.map +1 -0
- package/dist/cjs/pinner.d.cts +81 -0
- package/dist/cjs/types/constants.cjs +39 -0
- package/dist/cjs/types/constants.cjs.map +1 -0
- package/dist/cjs/types/mime-types.cjs +11 -0
- package/dist/cjs/types/mime-types.cjs.map +1 -0
- package/dist/cjs/types/mime-types.d.cts +7 -0
- package/dist/cjs/types/pin.d.cts +78 -0
- package/dist/cjs/types/type-guards.cjs +20 -0
- package/dist/cjs/types/type-guards.cjs.map +1 -0
- package/dist/cjs/types/type-guards.d.cts +15 -0
- package/dist/cjs/types/upload.cjs +18 -0
- package/dist/cjs/types/upload.cjs.map +1 -0
- package/dist/cjs/types/upload.d.cts +189 -0
- package/dist/cjs/upload/base-upload.cjs +135 -0
- package/dist/cjs/upload/base-upload.cjs.map +1 -0
- package/dist/cjs/upload/builder.cjs +174 -0
- package/dist/cjs/upload/builder.cjs.map +1 -0
- package/dist/cjs/upload/builder.d.cts +60 -0
- package/dist/cjs/upload/car.cjs +129 -0
- package/dist/cjs/upload/car.cjs.map +1 -0
- package/dist/cjs/upload/car.d.cts +19 -0
- package/dist/cjs/upload/constants.cjs +9 -0
- package/dist/cjs/upload/constants.cjs.map +1 -0
- package/dist/cjs/upload/index.cjs +8 -0
- package/dist/cjs/upload/manager.cjs +249 -0
- package/dist/cjs/upload/manager.cjs.map +1 -0
- package/dist/cjs/upload/manager.d.cts +35 -0
- package/dist/cjs/upload/normalize.cjs +28 -0
- package/dist/cjs/upload/normalize.cjs.map +1 -0
- package/dist/cjs/upload/tus-upload.cjs +74 -0
- package/dist/cjs/upload/tus-upload.cjs.map +1 -0
- package/dist/cjs/upload/xhr-upload.cjs +41 -0
- package/dist/cjs/upload/xhr-upload.cjs.map +1 -0
- package/dist/cjs/utils/env.cjs +12 -0
- package/dist/cjs/utils/env.cjs.map +1 -0
- package/dist/cjs/utils/stream.cjs +141 -0
- package/dist/cjs/utils/stream.cjs.map +1 -0
- package/dist/cjs/utils/stream.d.cts +23 -0
- package/dist/cjs/utils/tus-patch.cjs +50 -0
- package/dist/cjs/utils/tus-patch.cjs.map +1 -0
- package/dist/cjs/utils/validation.cjs +62 -0
- package/dist/cjs/utils/validation.cjs.map +1 -0
- package/dist/esm/_virtual/rolldown_runtime.js +8 -0
- package/dist/esm/adapters/pinata/index.d.ts +7 -0
- package/dist/esm/adapters/pinata/index.js +6 -0
- package/dist/esm/adapters/pinata/legacy/adapter.d.ts +74 -0
- package/dist/esm/adapters/pinata/legacy/adapter.js +83 -0
- package/dist/esm/adapters/pinata/legacy/adapter.js.map +1 -0
- package/dist/esm/adapters/pinata/legacy/index.d.ts +1 -0
- package/dist/esm/adapters/pinata/legacy/index.js +1 -0
- package/dist/esm/adapters/pinata/shared/index.d.ts +2 -0
- package/dist/esm/adapters/pinata/shared/index.js +1 -0
- package/dist/esm/adapters/pinata/shared/types.d.ts +218 -0
- package/dist/esm/adapters/pinata/shared/utils.d.ts +1 -0
- package/dist/esm/adapters/pinata/shared/utils.js +78 -0
- package/dist/esm/adapters/pinata/shared/utils.js.map +1 -0
- package/dist/esm/adapters/pinata/v2/adapter-interface.d.ts +198 -0
- package/dist/esm/adapters/pinata/v2/adapter.d.ts +17 -0
- package/dist/esm/adapters/pinata/v2/adapter.js +636 -0
- package/dist/esm/adapters/pinata/v2/adapter.js.map +1 -0
- package/dist/esm/adapters/pinata/v2/index.d.ts +3 -0
- package/dist/esm/adapters/pinata/v2/index.js +1 -0
- package/dist/esm/adapters/pinata/v2/types.d.ts +308 -0
- package/dist/esm/blockstore/index.d.ts +2 -0
- package/dist/esm/blockstore/index.js +2 -0
- package/dist/esm/blockstore/unstorage-base.d.ts +23 -0
- package/dist/esm/blockstore/unstorage-base.js +231 -0
- package/dist/esm/blockstore/unstorage-base.js.map +1 -0
- package/dist/esm/blockstore/unstorage.d.ts +36 -0
- package/dist/esm/blockstore/unstorage.js +38 -0
- package/dist/esm/blockstore/unstorage.js.map +1 -0
- package/dist/esm/config.d.ts +51 -0
- package/dist/esm/encoder/base64.js +37 -0
- package/dist/esm/encoder/base64.js.map +1 -0
- package/dist/esm/encoder/csv/csv-formatter.js +81 -0
- package/dist/esm/encoder/csv/csv-formatter.js.map +1 -0
- package/dist/esm/encoder/csv/field-formatter.js +75 -0
- package/dist/esm/encoder/csv/field-formatter.js.map +1 -0
- package/dist/esm/encoder/csv/row-formatter.js +159 -0
- package/dist/esm/encoder/csv/row-formatter.js.map +1 -0
- package/dist/esm/encoder/csv.js +43 -0
- package/dist/esm/encoder/csv.js.map +1 -0
- package/dist/esm/encoder/error.js +18 -0
- package/dist/esm/encoder/error.js.map +1 -0
- package/dist/esm/encoder/index.js +6 -0
- package/dist/esm/encoder/json.js +35 -0
- package/dist/esm/encoder/json.js.map +1 -0
- package/dist/esm/encoder/text.js +34 -0
- package/dist/esm/encoder/text.js.map +1 -0
- package/dist/esm/encoder/url.js +36 -0
- package/dist/esm/encoder/url.js.map +1 -0
- package/dist/esm/errors/index.d.ts +47 -0
- package/dist/esm/errors/index.js +93 -0
- package/dist/esm/errors/index.js.map +1 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/pin/client.js +97 -0
- package/dist/esm/pin/client.js.map +1 -0
- package/dist/esm/pin/index.js +1 -0
- package/dist/esm/pinner.d.ts +81 -0
- package/dist/esm/pinner.js +131 -0
- package/dist/esm/pinner.js.map +1 -0
- package/dist/esm/types/constants.js +33 -0
- package/dist/esm/types/constants.js.map +1 -0
- package/dist/esm/types/mime-types.d.ts +7 -0
- package/dist/esm/types/mime-types.js +8 -0
- package/dist/esm/types/mime-types.js.map +1 -0
- package/dist/esm/types/pin.d.ts +78 -0
- package/dist/esm/types/type-guards.d.ts +15 -0
- package/dist/esm/types/type-guards.js +19 -0
- package/dist/esm/types/type-guards.js.map +1 -0
- package/dist/esm/types/upload.d.ts +189 -0
- package/dist/esm/types/upload.js +16 -0
- package/dist/esm/types/upload.js.map +1 -0
- package/dist/esm/upload/base-upload.js +132 -0
- package/dist/esm/upload/base-upload.js.map +1 -0
- package/dist/esm/upload/builder.d.ts +60 -0
- package/dist/esm/upload/builder.js +173 -0
- package/dist/esm/upload/builder.js.map +1 -0
- package/dist/esm/upload/car.d.ts +19 -0
- package/dist/esm/upload/car.js +125 -0
- package/dist/esm/upload/car.js.map +1 -0
- package/dist/esm/upload/constants.js +7 -0
- package/dist/esm/upload/constants.js.map +1 -0
- package/dist/esm/upload/index.js +8 -0
- package/dist/esm/upload/manager.d.ts +35 -0
- package/dist/esm/upload/manager.js +248 -0
- package/dist/esm/upload/manager.js.map +1 -0
- package/dist/esm/upload/normalize.js +28 -0
- package/dist/esm/upload/normalize.js.map +1 -0
- package/dist/esm/upload/tus-upload.js +72 -0
- package/dist/esm/upload/tus-upload.js.map +1 -0
- package/dist/esm/upload/xhr-upload.js +39 -0
- package/dist/esm/upload/xhr-upload.js.map +1 -0
- package/dist/esm/utils/env.js +11 -0
- package/dist/esm/utils/env.js.map +1 -0
- package/dist/esm/utils/stream.d.ts +23 -0
- package/dist/esm/utils/stream.js +134 -0
- package/dist/esm/utils/stream.js.map +1 -0
- package/dist/esm/utils/tus-patch.js +51 -0
- package/dist/esm/utils/tus-patch.js.map +1 -0
- package/dist/esm/utils/validation.js +60 -0
- package/dist/esm/utils/validation.js.map +1 -0
- package/package.json +95 -8
- package/public/mockServiceWorker.js +349 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unstorage.js","names":[],"sources":["../../../src/blockstore/unstorage.ts"],"sourcesContent":["import {\n createUnstorageBlockstore,\n createUnstorageDatastore,\n driverFactory,\n setDriverFactory,\n type UnstorageBlockstoreOptions,\n} from \"./unstorage-base\";\nimport {\n DEFAULT_BLOCKSTORE_BASE,\n DEFAULT_BLOCKSTORE_FS_BASE,\n} from \"@/types/constants\";\n\nfunction isBrowser(): boolean {\n return (\n typeof window !== \"undefined\" && typeof window.localStorage !== \"undefined\"\n );\n}\n\nasync function getDefaultDriver(base?: string) {\n // Use driverFactory override if set (typically by tests to inject in-memory driver)\n if (driverFactory) {\n return await driverFactory();\n }\n\n if (isBrowser()) {\n return (await import(\"unstorage/drivers/indexedb\")).default({\n base: base ?? DEFAULT_BLOCKSTORE_BASE,\n });\n } else {\n return (await import(\"unstorage/drivers/fs-lite\")).default({\n base: base ?? DEFAULT_BLOCKSTORE_FS_BASE,\n });\n }\n}\n\nexport function createBlockstore(options?: UnstorageBlockstoreOptions) {\n const BlockstoreClass = createUnstorageBlockstore(getDefaultDriver);\n return class extends BlockstoreClass {\n constructor(instanceOptions?: UnstorageBlockstoreOptions) {\n super({ ...options, ...instanceOptions });\n }\n };\n}\n\nexport function createDatastore(options?: UnstorageBlockstoreOptions) {\n const DatastoreClass = createUnstorageDatastore(getDefaultDriver);\n return class extends DatastoreClass {\n constructor(instanceOptions?: UnstorageBlockstoreOptions) {\n super({ ...options, ...instanceOptions });\n }\n };\n}\n\nexport { setDriverFactory };\nexport type { UnstorageBlockstoreOptions } from \"./unstorage-base\";\n"],"mappings":";;;;AAYA,SAAS,YAAqB;AAC5B,QACE,OAAO,WAAW,eAAe,OAAO,OAAO,iBAAiB;;AAIpE,eAAe,iBAAiB,MAAe;AAE7C,KAAI,cACF,QAAO,MAAM,eAAe;AAG9B,KAAI,WAAW,CACb,SAAQ,MAAM,OAAO,+BAA+B,QAAQ,EAC1D,MAAM,QAAQ,yBACf,CAAC;KAEF,SAAQ,MAAM,OAAO,8BAA8B,QAAQ,EACzD,MAAM,QAAQ,4BACf,CAAC;;AAIN,SAAgB,iBAAiB,SAAsC;CACrE,MAAM,kBAAkB,0BAA0B,iBAAiB;AACnE,QAAO,cAAc,gBAAgB;EACnC,YAAY,iBAA8C;AACxD,SAAM;IAAE,GAAG;IAAS,GAAG;IAAiB,CAAC;;;;AAK/C,SAAgB,gBAAgB,SAAsC;CACpE,MAAM,iBAAiB,yBAAyB,iBAAiB;AACjE,QAAO,cAAc,eAAe;EAClC,YAAY,iBAA8C;AACxD,SAAM;IAAE,GAAG;IAAS,GAAG;IAAiB,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Storage } from "unstorage";
|
|
2
|
+
import { Datastore } from "interface-datastore";
|
|
3
|
+
|
|
4
|
+
//#region src/config.d.ts
|
|
5
|
+
interface PinnerConfig {
|
|
6
|
+
/**
|
|
7
|
+
* JWT authentication token. Required for all API operations.
|
|
8
|
+
*/
|
|
9
|
+
jwt: string;
|
|
10
|
+
/**
|
|
11
|
+
* API endpoint URL. Defaults to the official pinning service.
|
|
12
|
+
* @default "https://ipfs.pinner.xyz"
|
|
13
|
+
*/
|
|
14
|
+
endpoint?: string;
|
|
15
|
+
/**
|
|
16
|
+
* IPFS gateway URL for content retrieval.
|
|
17
|
+
* @default "https://dweb.link"
|
|
18
|
+
*/
|
|
19
|
+
gateway?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Allowed MIME types for upload. If undefined, all types allowed.
|
|
22
|
+
*/
|
|
23
|
+
allowedFileTypes?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Custom fetch implementation.
|
|
26
|
+
*/
|
|
27
|
+
fetch?: typeof fetch;
|
|
28
|
+
/**
|
|
29
|
+
* Custom datastore instance for Helia.
|
|
30
|
+
* If provided, this datastore will be used directly without creating one from storage.
|
|
31
|
+
* Highest priority - takes precedence over storage and datastoreName.
|
|
32
|
+
*/
|
|
33
|
+
datastore?: Datastore;
|
|
34
|
+
/**
|
|
35
|
+
* Custom storage instance for both Helia blockstore and datastore.
|
|
36
|
+
* If provided, this storage will be used instead of creating default storage.
|
|
37
|
+
* The storage instance must implement the unstorage Storage interface.
|
|
38
|
+
* Used when datastore is not provided.
|
|
39
|
+
*/
|
|
40
|
+
storage?: Storage;
|
|
41
|
+
/**
|
|
42
|
+
* Custom base name for Helia storage.
|
|
43
|
+
* Passed as the `base` option to both blockstore and datastore storage instances.
|
|
44
|
+
* Only used when neither datastore nor storage are provided.
|
|
45
|
+
* @default "pinner-helia-data"
|
|
46
|
+
*/
|
|
47
|
+
datastoreName?: string;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { PinnerConfig };
|
|
51
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EncoderError } from "./error.js";
|
|
2
|
+
|
|
3
|
+
//#region src/encoder/base64.ts
|
|
4
|
+
/**
|
|
5
|
+
* Base64 encoder - converts base64 strings to File objects.
|
|
6
|
+
*/
|
|
7
|
+
var Base64Encoder = class {
|
|
8
|
+
async encode(base64String, options) {
|
|
9
|
+
try {
|
|
10
|
+
const binaryString = atob(base64String);
|
|
11
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
12
|
+
for (let i = 0; i < binaryString.length; i++) bytes[i] = binaryString.charCodeAt(i);
|
|
13
|
+
const blob = new Blob([bytes], { type: "application/octet-stream" });
|
|
14
|
+
const filename = options?.name || "file.bin";
|
|
15
|
+
return {
|
|
16
|
+
file: new File([blob], filename, { type: "application/octet-stream" }),
|
|
17
|
+
options: {
|
|
18
|
+
name: options?.name,
|
|
19
|
+
keyvalues: options?.keyvalues
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof Error) throw new EncoderError(`Base64 encoding failed: ${error.message}`, "INVALID_BASE64", error);
|
|
24
|
+
throw new EncoderError("Base64 encoding failed: unknown error", "INVALID_BASE64");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Encode a base64 string to a File object.
|
|
30
|
+
*/
|
|
31
|
+
async function base64ToFile(base64String, options) {
|
|
32
|
+
return new Base64Encoder().encode(base64String, options);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
export { Base64Encoder, base64ToFile };
|
|
37
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.js","names":[],"sources":["../../../src/encoder/base64.ts"],"sourcesContent":["import type { Encoder, EncoderResult, UploadOptions } from \"./types\";\nimport { EncoderError } from \"./error\";\n\n/**\n * Base64 encoder - converts base64 strings to File objects.\n */\nexport class Base64Encoder implements Encoder<string> {\n async encode(\n base64String: string,\n options?: UploadOptions,\n ): Promise<EncoderResult> {\n try {\n const binaryString = atob(base64String);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const blob = new Blob([bytes], { type: \"application/octet-stream\" });\n const filename = options?.name || \"file.bin\";\n const file = new File([blob], filename, {\n type: \"application/octet-stream\",\n });\n\n return {\n file,\n options: {\n name: options?.name,\n keyvalues: options?.keyvalues,\n },\n };\n } catch (error) {\n if (error instanceof Error) {\n throw new EncoderError(\n `Base64 encoding failed: ${error.message}`,\n \"INVALID_BASE64\",\n error,\n );\n }\n throw new EncoderError(\n \"Base64 encoding failed: unknown error\",\n \"INVALID_BASE64\",\n );\n }\n }\n}\n\n/**\n * Encode a base64 string to a File object.\n */\nexport async function base64ToFile(\n base64String: string,\n options?: UploadOptions,\n): Promise<EncoderResult> {\n const encoder = new Base64Encoder();\n return encoder.encode(base64String, options);\n}\n"],"mappings":";;;;;;AAMA,IAAa,gBAAb,MAAsD;CACpD,MAAM,OACJ,cACA,SACwB;AACxB,MAAI;GACF,MAAM,eAAe,KAAK,aAAa;GACvC,MAAM,QAAQ,IAAI,WAAW,aAAa,OAAO;AACjD,QAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACvC,OAAM,KAAK,aAAa,WAAW,EAAE;GAEvC,MAAM,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,4BAA4B,CAAC;GACpE,MAAM,WAAW,SAAS,QAAQ;AAKlC,UAAO;IACL,MALW,IAAI,KAAK,CAAC,KAAK,EAAE,UAAU,EACtC,MAAM,4BACP,CAAC;IAIA,SAAS;KACP,MAAM,SAAS;KACf,WAAW,SAAS;KACrB;IACF;WACM,OAAO;AACd,OAAI,iBAAiB,MACnB,OAAM,IAAI,aACR,2BAA2B,MAAM,WACjC,kBACA,MACD;AAEH,SAAM,IAAI,aACR,yCACA,iBACD;;;;;;;AAQP,eAAsB,aACpB,cACA,SACwB;AAExB,QADgB,IAAI,eAAe,CACpB,OAAO,cAAc,QAAQ"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { RowFormatter } from "./row-formatter.js";
|
|
2
|
+
|
|
3
|
+
//#region src/encoder/csv/csv-formatter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Simple CSV formatter without streaming support.
|
|
6
|
+
* Converts arrays of objects or arrays to CSV strings.
|
|
7
|
+
*
|
|
8
|
+
* This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)
|
|
9
|
+
* Copyright (c) 2011 C2FO Labs, LLC
|
|
10
|
+
* Licensed under the MIT License
|
|
11
|
+
*/
|
|
12
|
+
var CsvFormatter = class {
|
|
13
|
+
options;
|
|
14
|
+
rowFormatter;
|
|
15
|
+
hasWrittenBOM = false;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.options = {
|
|
18
|
+
objectMode: true,
|
|
19
|
+
delimiter: ",",
|
|
20
|
+
rowDelimiter: "\n",
|
|
21
|
+
quote: "\"",
|
|
22
|
+
escape: void 0,
|
|
23
|
+
quoteColumns: false,
|
|
24
|
+
quoteHeaders: void 0,
|
|
25
|
+
headers: null,
|
|
26
|
+
writeHeaders: void 0,
|
|
27
|
+
includeEndRowDelimiter: false,
|
|
28
|
+
transform: void 0,
|
|
29
|
+
writeBOM: false,
|
|
30
|
+
BOM: "",
|
|
31
|
+
alwaysWriteHeaders: false,
|
|
32
|
+
...options
|
|
33
|
+
};
|
|
34
|
+
if (typeof this.options.escape !== "string") this.options.escape = this.options.quote === true ? "\"" : this.options.quote;
|
|
35
|
+
if (typeof this.options.quoteHeaders === "undefined") this.options.quoteHeaders = this.options.quoteColumns;
|
|
36
|
+
if (this.options.quote === true) this.options.quote = "\"";
|
|
37
|
+
else if (this.options.quote === false) this.options.quote = "";
|
|
38
|
+
this.rowFormatter = new RowFormatter(this.options);
|
|
39
|
+
this.hasWrittenBOM = !this.options.writeBOM;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Format an array of rows to CSV string.
|
|
43
|
+
*/
|
|
44
|
+
format(rows) {
|
|
45
|
+
const chunks = [];
|
|
46
|
+
if (!this.hasWrittenBOM) {
|
|
47
|
+
chunks.push(this.options.BOM || "");
|
|
48
|
+
this.hasWrittenBOM = true;
|
|
49
|
+
}
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
const formattedRows = this.rowFormatter.format(row);
|
|
52
|
+
chunks.push(...formattedRows);
|
|
53
|
+
}
|
|
54
|
+
const finishRows = this.rowFormatter.finish();
|
|
55
|
+
chunks.push(...finishRows);
|
|
56
|
+
return chunks.join("");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Format a single row to CSV string.
|
|
60
|
+
*/
|
|
61
|
+
formatRow(row) {
|
|
62
|
+
const chunks = [];
|
|
63
|
+
if (!this.hasWrittenBOM) {
|
|
64
|
+
chunks.push(this.options.BOM || "");
|
|
65
|
+
this.hasWrittenBOM = true;
|
|
66
|
+
}
|
|
67
|
+
const formattedRows = this.rowFormatter.format(row);
|
|
68
|
+
chunks.push(...formattedRows);
|
|
69
|
+
return chunks.join("");
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Create a CSV formatter with the given options.
|
|
74
|
+
*/
|
|
75
|
+
function createCsvFormatter(options) {
|
|
76
|
+
return new CsvFormatter(options);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { createCsvFormatter };
|
|
81
|
+
//# sourceMappingURL=csv-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-formatter.js","names":[],"sources":["../../../../src/encoder/csv/csv-formatter.ts"],"sourcesContent":["import type { CsvFormatterOptions } from \"./csv-options\";\nimport { RowFormatter } from \"./row-formatter\";\n\nexport type { CsvFormatterOptions };\n\n/**\n * Simple CSV formatter without streaming support.\n * Converts arrays of objects or arrays to CSV strings.\n *\n * This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)\n * Copyright (c) 2011 C2FO Labs, LLC\n * Licensed under the MIT License\n */\nexport class CsvFormatter {\n private options: CsvFormatterOptions;\n private rowFormatter: RowFormatter;\n private hasWrittenBOM = false;\n\n constructor(options: CsvFormatterOptions = {}) {\n this.options = {\n objectMode: true,\n delimiter: \",\",\n rowDelimiter: \"\\n\",\n quote: '\"',\n escape: undefined,\n quoteColumns: false,\n quoteHeaders: undefined,\n headers: null as string[] | null,\n writeHeaders: undefined,\n includeEndRowDelimiter: false,\n transform: undefined,\n writeBOM: false,\n BOM: \"\\ufeff\",\n alwaysWriteHeaders: false,\n ...options,\n };\n\n // Set escape to quote if not provided\n if (typeof this.options.escape !== \"string\") {\n this.options.escape =\n this.options.quote === true ? '\"' : (this.options.quote as string);\n }\n\n // Set quoteHeaders to quoteColumns if not provided\n if (typeof this.options.quoteHeaders === \"undefined\") {\n this.options.quoteHeaders = this.options.quoteColumns;\n }\n\n // Normalize quote option\n if (this.options.quote === true) {\n this.options.quote = '\"';\n } else if (this.options.quote === false) {\n this.options.quote = \"\";\n }\n\n this.rowFormatter = new RowFormatter(this.options);\n this.hasWrittenBOM = !this.options.writeBOM;\n }\n\n /**\n * Format an array of rows to CSV string.\n */\n format(rows: unknown[]): string {\n const chunks: string[] = [];\n\n // Write BOM if configured\n if (!this.hasWrittenBOM) {\n chunks.push(this.options.BOM || \"\\ufeff\");\n this.hasWrittenBOM = true;\n }\n\n // Format each row\n for (const row of rows) {\n const formattedRows = this.rowFormatter.format(row);\n chunks.push(...formattedRows);\n }\n\n // Add finish content (end row delimiter, etc.)\n const finishRows = this.rowFormatter.finish();\n chunks.push(...finishRows);\n\n return chunks.join(\"\");\n }\n\n /**\n * Format a single row to CSV string.\n */\n formatRow(row: unknown): string {\n const chunks: string[] = [];\n\n // Write BOM if configured\n if (!this.hasWrittenBOM) {\n chunks.push(this.options.BOM || \"\\ufeff\");\n this.hasWrittenBOM = true;\n }\n\n const formattedRows = this.rowFormatter.format(row);\n chunks.push(...formattedRows);\n\n return chunks.join(\"\");\n }\n}\n\n/**\n * Create a CSV formatter with the given options.\n */\nexport function createCsvFormatter(\n options?: CsvFormatterOptions,\n): CsvFormatter {\n return new CsvFormatter(options);\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAa,eAAb,MAA0B;CACxB,AAAQ;CACR,AAAQ;CACR,AAAQ,gBAAgB;CAExB,YAAY,UAA+B,EAAE,EAAE;AAC7C,OAAK,UAAU;GACb,YAAY;GACZ,WAAW;GACX,cAAc;GACd,OAAO;GACP,QAAQ;GACR,cAAc;GACd,cAAc;GACd,SAAS;GACT,cAAc;GACd,wBAAwB;GACxB,WAAW;GACX,UAAU;GACV,KAAK;GACL,oBAAoB;GACpB,GAAG;GACJ;AAGD,MAAI,OAAO,KAAK,QAAQ,WAAW,SACjC,MAAK,QAAQ,SACX,KAAK,QAAQ,UAAU,OAAO,OAAO,KAAK,QAAQ;AAItD,MAAI,OAAO,KAAK,QAAQ,iBAAiB,YACvC,MAAK,QAAQ,eAAe,KAAK,QAAQ;AAI3C,MAAI,KAAK,QAAQ,UAAU,KACzB,MAAK,QAAQ,QAAQ;WACZ,KAAK,QAAQ,UAAU,MAChC,MAAK,QAAQ,QAAQ;AAGvB,OAAK,eAAe,IAAI,aAAa,KAAK,QAAQ;AAClD,OAAK,gBAAgB,CAAC,KAAK,QAAQ;;;;;CAMrC,OAAO,MAAyB;EAC9B,MAAM,SAAmB,EAAE;AAG3B,MAAI,CAAC,KAAK,eAAe;AACvB,UAAO,KAAK,KAAK,QAAQ,OAAO,IAAS;AACzC,QAAK,gBAAgB;;AAIvB,OAAK,MAAM,OAAO,MAAM;GACtB,MAAM,gBAAgB,KAAK,aAAa,OAAO,IAAI;AACnD,UAAO,KAAK,GAAG,cAAc;;EAI/B,MAAM,aAAa,KAAK,aAAa,QAAQ;AAC7C,SAAO,KAAK,GAAG,WAAW;AAE1B,SAAO,OAAO,KAAK,GAAG;;;;;CAMxB,UAAU,KAAsB;EAC9B,MAAM,SAAmB,EAAE;AAG3B,MAAI,CAAC,KAAK,eAAe;AACvB,UAAO,KAAK,KAAK,QAAQ,OAAO,IAAS;AACzC,QAAK,gBAAgB;;EAGvB,MAAM,gBAAgB,KAAK,aAAa,OAAO,IAAI;AACnD,SAAO,KAAK,GAAG,cAAc;AAE7B,SAAO,OAAO,KAAK,GAAG;;;;;;AAO1B,SAAgB,mBACd,SACc;AACd,QAAO,IAAI,aAAa,QAAQ"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//#region src/encoder/csv/field-formatter.ts
|
|
2
|
+
/**
|
|
3
|
+
* Escape special regex characters in a string.
|
|
4
|
+
*/
|
|
5
|
+
function escapeRegExp(str) {
|
|
6
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Handles formatting of individual CSV fields including quoting and escaping.
|
|
10
|
+
*
|
|
11
|
+
* This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)
|
|
12
|
+
* Copyright (c) 2011 C2FO Labs, LLC
|
|
13
|
+
* Licensed under the MIT License
|
|
14
|
+
*/
|
|
15
|
+
var FieldFormatter = class {
|
|
16
|
+
options;
|
|
17
|
+
_headers = null;
|
|
18
|
+
quoteReplaceRegExp;
|
|
19
|
+
escapePatternRegExp;
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.options = options;
|
|
22
|
+
if (Array.isArray(options.headers)) this._headers = options.headers;
|
|
23
|
+
else this._headers = null;
|
|
24
|
+
const quote = options.quote === true ? "\"" : options.quote === false ? "" : options.quote ?? "\"";
|
|
25
|
+
this.quoteReplaceRegExp = new RegExp(quote, "g");
|
|
26
|
+
const escapePattern = `[${escapeRegExp(options.delimiter ?? ",")}${escapeRegExp(options.rowDelimiter ?? "\n")}|\r|\n]`;
|
|
27
|
+
this.escapePatternRegExp = new RegExp(escapePattern);
|
|
28
|
+
}
|
|
29
|
+
get headers() {
|
|
30
|
+
return this._headers;
|
|
31
|
+
}
|
|
32
|
+
set headers(headers) {
|
|
33
|
+
this._headers = headers;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Escape special regex characters in a string.
|
|
37
|
+
*/
|
|
38
|
+
#escapeRegExpString(str) {
|
|
39
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Determine if a field should be quoted.
|
|
43
|
+
*/
|
|
44
|
+
shouldQuote(fieldIndex, isHeader) {
|
|
45
|
+
const quoteConfig = isHeader ? this.options.quoteHeaders : this.options.quoteColumns;
|
|
46
|
+
if (typeof quoteConfig === "boolean") return quoteConfig;
|
|
47
|
+
if (Array.isArray(quoteConfig)) return quoteConfig[fieldIndex] === true;
|
|
48
|
+
if (this._headers !== null && typeof quoteConfig === "object") return quoteConfig[this._headers[fieldIndex]] === true;
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Format a single field value.
|
|
53
|
+
*/
|
|
54
|
+
format(field, fieldIndex, isHeader) {
|
|
55
|
+
const quote = this.options.quote === true ? "\"" : this.options.quote === false ? "" : this.options.quote ?? "\"";
|
|
56
|
+
const escape = this.options.escape ?? quote;
|
|
57
|
+
const preparedField = `${field == null ? "" : field}`.replace(/\0/g, "");
|
|
58
|
+
if (quote !== "") {
|
|
59
|
+
if (preparedField.indexOf(quote) !== -1) return this.quoteField(preparedField.replace(this.quoteReplaceRegExp, `${escape}${quote}`));
|
|
60
|
+
}
|
|
61
|
+
if (preparedField.search(this.escapePatternRegExp) !== -1 || this.shouldQuote(fieldIndex, isHeader)) return this.quoteField(preparedField);
|
|
62
|
+
return preparedField;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Quote a field value.
|
|
66
|
+
*/
|
|
67
|
+
quoteField(field) {
|
|
68
|
+
const quote = this.options.quote === true ? "\"" : this.options.quote === false ? "" : this.options.quote ?? "\"";
|
|
69
|
+
return `${quote}${field}${quote}`;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
export { FieldFormatter };
|
|
75
|
+
//# sourceMappingURL=field-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-formatter.js","names":[],"sources":["../../../../src/encoder/csv/field-formatter.ts"],"sourcesContent":["import type { CsvFormatterOptions } from \"./csv-options\";\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Handles formatting of individual CSV fields including quoting and escaping.\n *\n * This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)\n * Copyright (c) 2011 C2FO Labs, LLC\n * Licensed under the MIT License\n */\nexport class FieldFormatter {\n private options: CsvFormatterOptions;\n private _headers: string[] | null = null;\n private quoteReplaceRegExp: RegExp;\n private escapePatternRegExp: RegExp;\n\n constructor(options: CsvFormatterOptions) {\n this.options = options;\n\n if (Array.isArray(options.headers)) {\n this._headers = options.headers;\n } else {\n this._headers = null;\n }\n\n const quote =\n options.quote === true\n ? '\"'\n : options.quote === false\n ? \"\"\n : (options.quote ?? '\"');\n this.quoteReplaceRegExp = new RegExp(quote, \"g\");\n\n // Use lodash.escapeRegExp pattern for delimiter and row delimiter\n const escapePattern = `[${escapeRegExp(options.delimiter ?? \",\")}${escapeRegExp(options.rowDelimiter ?? \"\\n\")}|\\r|\\n]`;\n this.escapePatternRegExp = new RegExp(escapePattern);\n }\n\n get headers(): string[] | null {\n return this._headers;\n }\n\n set headers(headers: string[] | null) {\n this._headers = headers;\n }\n\n /**\n * Escape special regex characters in a string.\n */\n #escapeRegExpString(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n }\n\n /**\n * Determine if a field should be quoted.\n */\n private shouldQuote(fieldIndex: number, isHeader: boolean): boolean {\n const quoteConfig = isHeader\n ? this.options.quoteHeaders\n : this.options.quoteColumns;\n\n if (typeof quoteConfig === \"boolean\") {\n return quoteConfig;\n }\n\n if (Array.isArray(quoteConfig)) {\n return quoteConfig[fieldIndex] === true;\n }\n\n if (this._headers !== null && typeof quoteConfig === \"object\") {\n return quoteConfig[this._headers[fieldIndex]] === true;\n }\n\n return false;\n }\n\n /**\n * Format a single field value.\n */\n format(field: unknown, fieldIndex: number, isHeader: boolean): string {\n const quote =\n this.options.quote === true\n ? '\"'\n : this.options.quote === false\n ? \"\"\n : (this.options.quote ?? '\"');\n const escape = this.options.escape ?? quote;\n\n // Convert to string, handle null/undefined\n const preparedField = `${field == null ? \"\" : field}`.replace(/\\0/g, \"\");\n\n // Handle quote escaping\n if (quote !== \"\") {\n const shouldEscape = preparedField.indexOf(quote) !== -1;\n if (shouldEscape) {\n return this.quoteField(\n preparedField.replace(this.quoteReplaceRegExp, `${escape}${quote}`),\n );\n }\n }\n\n // Check if field needs quoting (contains delimiter, row delimiter, etc.)\n const hasEscapeCharacters =\n preparedField.search(this.escapePatternRegExp) !== -1;\n if (hasEscapeCharacters || this.shouldQuote(fieldIndex, isHeader)) {\n return this.quoteField(preparedField);\n }\n\n return preparedField;\n }\n\n /**\n * Quote a field value.\n */\n private quoteField(field: string): string {\n const quote =\n this.options.quote === true\n ? '\"'\n : this.options.quote === false\n ? \"\"\n : (this.options.quote ?? '\"');\n return `${quote}${field}${quote}`;\n }\n}\n"],"mappings":";;;;AAKA,SAAS,aAAa,KAAqB;AACzC,QAAO,IAAI,QAAQ,uBAAuB,OAAO;;;;;;;;;AAUnD,IAAa,iBAAb,MAA4B;CAC1B,AAAQ;CACR,AAAQ,WAA4B;CACpC,AAAQ;CACR,AAAQ;CAER,YAAY,SAA8B;AACxC,OAAK,UAAU;AAEf,MAAI,MAAM,QAAQ,QAAQ,QAAQ,CAChC,MAAK,WAAW,QAAQ;MAExB,MAAK,WAAW;EAGlB,MAAM,QACJ,QAAQ,UAAU,OACd,OACA,QAAQ,UAAU,QAChB,KACC,QAAQ,SAAS;AAC1B,OAAK,qBAAqB,IAAI,OAAO,OAAO,IAAI;EAGhD,MAAM,gBAAgB,IAAI,aAAa,QAAQ,aAAa,IAAI,GAAG,aAAa,QAAQ,gBAAgB,KAAK,CAAC;AAC9G,OAAK,sBAAsB,IAAI,OAAO,cAAc;;CAGtD,IAAI,UAA2B;AAC7B,SAAO,KAAK;;CAGd,IAAI,QAAQ,SAA0B;AACpC,OAAK,WAAW;;;;;CAMlB,oBAAoB,KAAqB;AACvC,SAAO,IAAI,QAAQ,uBAAuB,OAAO;;;;;CAMnD,AAAQ,YAAY,YAAoB,UAA4B;EAClE,MAAM,cAAc,WAChB,KAAK,QAAQ,eACb,KAAK,QAAQ;AAEjB,MAAI,OAAO,gBAAgB,UACzB,QAAO;AAGT,MAAI,MAAM,QAAQ,YAAY,CAC5B,QAAO,YAAY,gBAAgB;AAGrC,MAAI,KAAK,aAAa,QAAQ,OAAO,gBAAgB,SACnD,QAAO,YAAY,KAAK,SAAS,iBAAiB;AAGpD,SAAO;;;;;CAMT,OAAO,OAAgB,YAAoB,UAA2B;EACpE,MAAM,QACJ,KAAK,QAAQ,UAAU,OACnB,OACA,KAAK,QAAQ,UAAU,QACrB,KACC,KAAK,QAAQ,SAAS;EAC/B,MAAM,SAAS,KAAK,QAAQ,UAAU;EAGtC,MAAM,gBAAgB,GAAG,SAAS,OAAO,KAAK,QAAQ,QAAQ,OAAO,GAAG;AAGxE,MAAI,UAAU,IAEZ;OADqB,cAAc,QAAQ,MAAM,KAAK,GAEpD,QAAO,KAAK,WACV,cAAc,QAAQ,KAAK,oBAAoB,GAAG,SAAS,QAAQ,CACpE;;AAOL,MADE,cAAc,OAAO,KAAK,oBAAoB,KAAK,MAC1B,KAAK,YAAY,YAAY,SAAS,CAC/D,QAAO,KAAK,WAAW,cAAc;AAGvC,SAAO;;;;;CAMT,AAAQ,WAAW,OAAuB;EACxC,MAAM,QACJ,KAAK,QAAQ,UAAU,OACnB,OACA,KAAK,QAAQ,UAAU,QACrB,KACC,KAAK,QAAQ,SAAS;AAC/B,SAAO,GAAG,QAAQ,QAAQ"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { FieldFormatter } from "./field-formatter.js";
|
|
2
|
+
|
|
3
|
+
//#region src/encoder/csv/row-formatter.ts
|
|
4
|
+
/**
|
|
5
|
+
* Handles formatting of CSV rows including headers and column extraction.
|
|
6
|
+
*
|
|
7
|
+
* This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)
|
|
8
|
+
* Copyright (c) 2011 C2FO Labs, LLC
|
|
9
|
+
* Licensed under the MIT License
|
|
10
|
+
*/
|
|
11
|
+
var RowFormatter = class {
|
|
12
|
+
options;
|
|
13
|
+
fieldFormatter;
|
|
14
|
+
shouldWriteHeaders;
|
|
15
|
+
rowTransform = null;
|
|
16
|
+
headers = null;
|
|
17
|
+
hasWrittenHeaders = false;
|
|
18
|
+
rowCount = 0;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.fieldFormatter = new FieldFormatter(options);
|
|
22
|
+
this.headers = Array.isArray(options.headers) ? options.headers : null;
|
|
23
|
+
this.shouldWriteHeaders = options.writeHeaders ?? (Array.isArray(options.headers) || options.headers === true);
|
|
24
|
+
if (this.headers !== null) this.fieldFormatter.headers = this.headers;
|
|
25
|
+
if (options.transform) this.rowTransform = this.createTransform(options.transform);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a transform function that handles both sync and async transforms.
|
|
29
|
+
*/
|
|
30
|
+
createTransform(transformFn) {
|
|
31
|
+
if (transformFn.length === 1) return (row, cb) => {
|
|
32
|
+
try {
|
|
33
|
+
cb(null, transformFn(row));
|
|
34
|
+
} catch (e) {
|
|
35
|
+
cb(e instanceof Error ? e : new Error(String(e)));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
return transformFn;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if the transform is synchronous (arity 1).
|
|
42
|
+
*/
|
|
43
|
+
isSyncTransform() {
|
|
44
|
+
if (!this.options.transform) return true;
|
|
45
|
+
return this.options.transform.length === 1;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Format a single row.
|
|
49
|
+
*/
|
|
50
|
+
format(row) {
|
|
51
|
+
let transformedRow;
|
|
52
|
+
if (this.rowTransform) transformedRow = this.applyTransformSync(row);
|
|
53
|
+
else transformedRow = row;
|
|
54
|
+
if (!transformedRow) return [];
|
|
55
|
+
const rows = [];
|
|
56
|
+
const { shouldFormatColumns, headers } = this.checkHeaders(transformedRow);
|
|
57
|
+
if (this.shouldWriteHeaders && headers && !this.hasWrittenHeaders) {
|
|
58
|
+
rows.push(this.formatColumns(headers, true));
|
|
59
|
+
this.hasWrittenHeaders = true;
|
|
60
|
+
}
|
|
61
|
+
if (shouldFormatColumns) {
|
|
62
|
+
const columns = this.gatherColumns(transformedRow);
|
|
63
|
+
rows.push(this.formatColumns(columns, false));
|
|
64
|
+
}
|
|
65
|
+
return rows;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Apply transform synchronously.
|
|
69
|
+
* Note: This only supports sync transforms. Async transforms are not supported
|
|
70
|
+
* in the synchronous format() method.
|
|
71
|
+
*/
|
|
72
|
+
applyTransformSync(row) {
|
|
73
|
+
if (!this.options.transform) return row;
|
|
74
|
+
if (this.isSyncTransform()) try {
|
|
75
|
+
return this.options.transform(row);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
throw e instanceof Error ? e : new Error(String(e));
|
|
78
|
+
}
|
|
79
|
+
throw new Error("Async transforms are not supported in synchronous CSV formatting");
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Finish formatting and return any trailing content.
|
|
83
|
+
*/
|
|
84
|
+
finish() {
|
|
85
|
+
const rows = [];
|
|
86
|
+
if (this.options.alwaysWriteHeaders && this.rowCount === 0) {
|
|
87
|
+
if (!this.headers) throw new Error("`alwaysWriteHeaders` option is set to true but `headers` option not provided.");
|
|
88
|
+
rows.push(this.formatColumns(this.headers, true));
|
|
89
|
+
}
|
|
90
|
+
if (this.options.includeEndRowDelimiter) rows.push(this.options.rowDelimiter || "\n");
|
|
91
|
+
return rows;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if headers need to be written.
|
|
95
|
+
*/
|
|
96
|
+
checkHeaders(row) {
|
|
97
|
+
if (this.headers) return {
|
|
98
|
+
shouldFormatColumns: true,
|
|
99
|
+
headers: this.headers
|
|
100
|
+
};
|
|
101
|
+
const headers = this.gatherHeaders(row);
|
|
102
|
+
this.headers = headers;
|
|
103
|
+
this.fieldFormatter.headers = headers;
|
|
104
|
+
if (!this.shouldWriteHeaders) return {
|
|
105
|
+
shouldFormatColumns: true,
|
|
106
|
+
headers: null
|
|
107
|
+
};
|
|
108
|
+
if (Array.isArray(row) && headers.every((header, i) => header === row[i])) return {
|
|
109
|
+
shouldFormatColumns: false,
|
|
110
|
+
headers
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
shouldFormatColumns: true,
|
|
114
|
+
headers
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Extract headers from a row.
|
|
119
|
+
*/
|
|
120
|
+
gatherHeaders(row) {
|
|
121
|
+
if (this.isRowHashArray(row)) return row.map((it) => String(it[0]));
|
|
122
|
+
if (Array.isArray(row)) return row.map(String);
|
|
123
|
+
return Object.keys(row);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if row is a hash array (multi-dimensional array with [key, value] pairs).
|
|
127
|
+
*/
|
|
128
|
+
isRowHashArray(row) {
|
|
129
|
+
if (!Array.isArray(row)) return false;
|
|
130
|
+
return Array.isArray(row[0]) && row[0].length === 2;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Extract column values from a row.
|
|
134
|
+
*/
|
|
135
|
+
gatherColumns(row) {
|
|
136
|
+
if (this.headers === null) throw new Error("Headers is currently null");
|
|
137
|
+
if (!Array.isArray(row)) return this.headers.map((header) => row[header]);
|
|
138
|
+
if (this.isRowHashArray(row)) return this.headers.map((header, i) => {
|
|
139
|
+
const col = row[i];
|
|
140
|
+
return col ? col[1] : "";
|
|
141
|
+
});
|
|
142
|
+
if (!this.shouldWriteHeaders) return row;
|
|
143
|
+
return this.headers.map((_, i) => row[i]);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Format columns into a CSV row string.
|
|
147
|
+
*/
|
|
148
|
+
formatColumns(columns, isHeadersRow) {
|
|
149
|
+
const formattedCols = columns.map((field, i) => this.fieldFormatter.format(field, i, isHeadersRow)).join(this.options.delimiter || ",");
|
|
150
|
+
const { rowCount } = this;
|
|
151
|
+
this.rowCount += 1;
|
|
152
|
+
if (rowCount > 0) return [this.options.rowDelimiter || "\n", formattedCols].join("");
|
|
153
|
+
return formattedCols;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
export { RowFormatter };
|
|
159
|
+
//# sourceMappingURL=row-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-formatter.js","names":[],"sources":["../../../../src/encoder/csv/row-formatter.ts"],"sourcesContent":["import type {\n CsvFormatterOptions,\n RowTransform,\n RowTransformCallback,\n} from \"./csv-options\";\nimport { FieldFormatter } from \"./field-formatter\";\n\n/**\n * Handles formatting of CSV rows including headers and column extraction.\n *\n * This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)\n * Copyright (c) 2011 C2FO Labs, LLC\n * Licensed under the MIT License\n */\nexport class RowFormatter {\n private options: CsvFormatterOptions;\n private fieldFormatter: FieldFormatter;\n private shouldWriteHeaders: boolean;\n private rowTransform: RowTransformCallback | null = null;\n private headers: string[] | null = null;\n private hasWrittenHeaders = false;\n private rowCount = 0;\n\n constructor(options: CsvFormatterOptions) {\n this.options = options;\n this.fieldFormatter = new FieldFormatter(options);\n this.headers = Array.isArray(options.headers) ? options.headers : null;\n this.shouldWriteHeaders =\n options.writeHeaders ??\n (Array.isArray(options.headers) || options.headers === true);\n\n if (this.headers !== null) {\n this.fieldFormatter.headers = this.headers;\n }\n\n if (options.transform) {\n this.rowTransform = this.createTransform(options.transform);\n }\n }\n\n /**\n * Create a transform function that handles both sync and async transforms.\n */\n private createTransform(transformFn: RowTransform): RowTransformCallback {\n // Check if it's a sync transform (arity 1)\n if (transformFn.length === 1) {\n return (row: unknown, cb: RowTransformCallback) => {\n try {\n const transformedRow = (transformFn as (row: unknown) => unknown)(\n row,\n );\n cb(null, transformedRow);\n } catch (e) {\n cb(e instanceof Error ? e : new Error(String(e)));\n }\n };\n }\n\n return transformFn as RowTransformCallback;\n }\n\n /**\n * Check if the transform is synchronous (arity 1).\n */\n private isSyncTransform(): boolean {\n if (!this.options.transform) {\n return true;\n }\n return this.options.transform.length === 1;\n }\n\n /**\n * Format a single row.\n */\n format(row: unknown): string[] {\n let transformedRow: unknown;\n\n // Apply transform if present\n if (this.rowTransform) {\n transformedRow = this.applyTransformSync(row);\n } else {\n transformedRow = row;\n }\n\n if (!transformedRow) {\n return [];\n }\n\n const rows: string[] = [];\n\n // Check headers\n const { shouldFormatColumns, headers } = this.checkHeaders(transformedRow);\n\n // Write headers if needed\n if (this.shouldWriteHeaders && headers && !this.hasWrittenHeaders) {\n rows.push(this.formatColumns(headers, true));\n this.hasWrittenHeaders = true;\n }\n\n // Format data row\n if (shouldFormatColumns) {\n const columns = this.gatherColumns(transformedRow);\n rows.push(this.formatColumns(columns, false));\n }\n\n return rows;\n }\n\n /**\n * Apply transform synchronously.\n * Note: This only supports sync transforms. Async transforms are not supported\n * in the synchronous format() method.\n */\n private applyTransformSync(row: unknown): unknown {\n if (!this.options.transform) {\n return row;\n }\n\n // Only sync transforms (arity 1) are supported\n if (this.isSyncTransform()) {\n try {\n return (this.options.transform as (row: unknown) => unknown)(row);\n } catch (e) {\n throw e instanceof Error ? e : new Error(String(e));\n }\n }\n\n throw new Error(\n \"Async transforms are not supported in synchronous CSV formatting\",\n );\n }\n\n /**\n * Finish formatting and return any trailing content.\n */\n finish(): string[] {\n const rows: string[] = [];\n\n // Write headers if alwaysWriteHeaders is true and no rows were written\n if (this.options.alwaysWriteHeaders && this.rowCount === 0) {\n if (!this.headers) {\n throw new Error(\n \"`alwaysWriteHeaders` option is set to true but `headers` option not provided.\",\n );\n }\n rows.push(this.formatColumns(this.headers, true));\n }\n\n // Add end row delimiter if configured\n if (this.options.includeEndRowDelimiter) {\n rows.push(this.options.rowDelimiter || \"\\n\");\n }\n\n return rows;\n }\n\n /**\n * Check if headers need to be written.\n */\n private checkHeaders(row: unknown): {\n shouldFormatColumns: boolean;\n headers: string[] | null;\n } {\n if (this.headers) {\n return { shouldFormatColumns: true, headers: this.headers };\n }\n\n const headers = this.gatherHeaders(row);\n this.headers = headers;\n this.fieldFormatter.headers = headers;\n\n if (!this.shouldWriteHeaders) {\n return { shouldFormatColumns: true, headers: null };\n }\n\n // If the row is equal to headers, don't format (it's the header row itself)\n if (Array.isArray(row) && headers.every((header, i) => header === row[i])) {\n return { shouldFormatColumns: false, headers };\n }\n\n return { shouldFormatColumns: true, headers };\n }\n\n /**\n * Extract headers from a row.\n */\n private gatherHeaders(row: unknown): string[] {\n if (this.isRowHashArray(row)) {\n // Multi-dimensional array with item 0 being the header\n return (row as unknown[][]).map((it) => String(it[0]));\n }\n\n if (Array.isArray(row)) {\n return row.map(String);\n }\n\n return Object.keys(row as object);\n }\n\n /**\n * Check if row is a hash array (multi-dimensional array with [key, value] pairs).\n */\n private isRowHashArray(row: unknown): boolean {\n if (!Array.isArray(row)) {\n return false;\n }\n return Array.isArray(row[0]) && row[0].length === 2;\n }\n\n /**\n * Extract column values from a row.\n */\n private gatherColumns(row: unknown): unknown[] {\n if (this.headers === null) {\n throw new Error(\"Headers is currently null\");\n }\n\n if (!Array.isArray(row)) {\n // Object: use headers to get values\n return this.headers.map(\n (header) => (row as Record<string, unknown>)[header],\n );\n }\n\n if (this.isRowHashArray(row)) {\n // Hash array: extract values\n return this.headers.map((header, i) => {\n const col = (row as unknown[][])[i];\n return col ? col[1] : \"\";\n });\n }\n\n // Regular array\n if (!this.shouldWriteHeaders) {\n // If headers weren't written, return the row as-is\n return row;\n }\n\n // Map by header index\n return this.headers.map((_, i) => row[i]);\n }\n\n /**\n * Format columns into a CSV row string.\n */\n private formatColumns(columns: unknown[], isHeadersRow: boolean): string {\n const formattedCols = columns\n .map((field, i) => this.fieldFormatter.format(field, i, isHeadersRow))\n .join(this.options.delimiter || \",\");\n\n const { rowCount } = this;\n this.rowCount += 1;\n\n // Add row delimiter before all rows except the first\n if (rowCount > 0) {\n return [this.options.rowDelimiter || \"\\n\", formattedCols].join(\"\");\n }\n\n return formattedCols;\n }\n}\n"],"mappings":";;;;;;;;;;AAcA,IAAa,eAAb,MAA0B;CACxB,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ,eAA4C;CACpD,AAAQ,UAA2B;CACnC,AAAQ,oBAAoB;CAC5B,AAAQ,WAAW;CAEnB,YAAY,SAA8B;AACxC,OAAK,UAAU;AACf,OAAK,iBAAiB,IAAI,eAAe,QAAQ;AACjD,OAAK,UAAU,MAAM,QAAQ,QAAQ,QAAQ,GAAG,QAAQ,UAAU;AAClE,OAAK,qBACH,QAAQ,iBACP,MAAM,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,YAAY;AAEzD,MAAI,KAAK,YAAY,KACnB,MAAK,eAAe,UAAU,KAAK;AAGrC,MAAI,QAAQ,UACV,MAAK,eAAe,KAAK,gBAAgB,QAAQ,UAAU;;;;;CAO/D,AAAQ,gBAAgB,aAAiD;AAEvE,MAAI,YAAY,WAAW,EACzB,SAAQ,KAAc,OAA6B;AACjD,OAAI;AAIF,OAAG,MAHqB,YACtB,IACD,CACuB;YACjB,GAAG;AACV,OAAG,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;;;AAKvD,SAAO;;;;;CAMT,AAAQ,kBAA2B;AACjC,MAAI,CAAC,KAAK,QAAQ,UAChB,QAAO;AAET,SAAO,KAAK,QAAQ,UAAU,WAAW;;;;;CAM3C,OAAO,KAAwB;EAC7B,IAAI;AAGJ,MAAI,KAAK,aACP,kBAAiB,KAAK,mBAAmB,IAAI;MAE7C,kBAAiB;AAGnB,MAAI,CAAC,eACH,QAAO,EAAE;EAGX,MAAM,OAAiB,EAAE;EAGzB,MAAM,EAAE,qBAAqB,YAAY,KAAK,aAAa,eAAe;AAG1E,MAAI,KAAK,sBAAsB,WAAW,CAAC,KAAK,mBAAmB;AACjE,QAAK,KAAK,KAAK,cAAc,SAAS,KAAK,CAAC;AAC5C,QAAK,oBAAoB;;AAI3B,MAAI,qBAAqB;GACvB,MAAM,UAAU,KAAK,cAAc,eAAe;AAClD,QAAK,KAAK,KAAK,cAAc,SAAS,MAAM,CAAC;;AAG/C,SAAO;;;;;;;CAQT,AAAQ,mBAAmB,KAAuB;AAChD,MAAI,CAAC,KAAK,QAAQ,UAChB,QAAO;AAIT,MAAI,KAAK,iBAAiB,CACxB,KAAI;AACF,UAAQ,KAAK,QAAQ,UAAwC,IAAI;WAC1D,GAAG;AACV,SAAM,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC;;AAIvD,QAAM,IAAI,MACR,mEACD;;;;;CAMH,SAAmB;EACjB,MAAM,OAAiB,EAAE;AAGzB,MAAI,KAAK,QAAQ,sBAAsB,KAAK,aAAa,GAAG;AAC1D,OAAI,CAAC,KAAK,QACR,OAAM,IAAI,MACR,gFACD;AAEH,QAAK,KAAK,KAAK,cAAc,KAAK,SAAS,KAAK,CAAC;;AAInD,MAAI,KAAK,QAAQ,uBACf,MAAK,KAAK,KAAK,QAAQ,gBAAgB,KAAK;AAG9C,SAAO;;;;;CAMT,AAAQ,aAAa,KAGnB;AACA,MAAI,KAAK,QACP,QAAO;GAAE,qBAAqB;GAAM,SAAS,KAAK;GAAS;EAG7D,MAAM,UAAU,KAAK,cAAc,IAAI;AACvC,OAAK,UAAU;AACf,OAAK,eAAe,UAAU;AAE9B,MAAI,CAAC,KAAK,mBACR,QAAO;GAAE,qBAAqB;GAAM,SAAS;GAAM;AAIrD,MAAI,MAAM,QAAQ,IAAI,IAAI,QAAQ,OAAO,QAAQ,MAAM,WAAW,IAAI,GAAG,CACvE,QAAO;GAAE,qBAAqB;GAAO;GAAS;AAGhD,SAAO;GAAE,qBAAqB;GAAM;GAAS;;;;;CAM/C,AAAQ,cAAc,KAAwB;AAC5C,MAAI,KAAK,eAAe,IAAI,CAE1B,QAAQ,IAAoB,KAAK,OAAO,OAAO,GAAG,GAAG,CAAC;AAGxD,MAAI,MAAM,QAAQ,IAAI,CACpB,QAAO,IAAI,IAAI,OAAO;AAGxB,SAAO,OAAO,KAAK,IAAc;;;;;CAMnC,AAAQ,eAAe,KAAuB;AAC5C,MAAI,CAAC,MAAM,QAAQ,IAAI,CACrB,QAAO;AAET,SAAO,MAAM,QAAQ,IAAI,GAAG,IAAI,IAAI,GAAG,WAAW;;;;;CAMpD,AAAQ,cAAc,KAAyB;AAC7C,MAAI,KAAK,YAAY,KACnB,OAAM,IAAI,MAAM,4BAA4B;AAG9C,MAAI,CAAC,MAAM,QAAQ,IAAI,CAErB,QAAO,KAAK,QAAQ,KACjB,WAAY,IAAgC,QAC9C;AAGH,MAAI,KAAK,eAAe,IAAI,CAE1B,QAAO,KAAK,QAAQ,KAAK,QAAQ,MAAM;GACrC,MAAM,MAAO,IAAoB;AACjC,UAAO,MAAM,IAAI,KAAK;IACtB;AAIJ,MAAI,CAAC,KAAK,mBAER,QAAO;AAIT,SAAO,KAAK,QAAQ,KAAK,GAAG,MAAM,IAAI,GAAG;;;;;CAM3C,AAAQ,cAAc,SAAoB,cAA+B;EACvE,MAAM,gBAAgB,QACnB,KAAK,OAAO,MAAM,KAAK,eAAe,OAAO,OAAO,GAAG,aAAa,CAAC,CACrE,KAAK,KAAK,QAAQ,aAAa,IAAI;EAEtC,MAAM,EAAE,aAAa;AACrB,OAAK,YAAY;AAGjB,MAAI,WAAW,EACb,QAAO,CAAC,KAAK,QAAQ,gBAAgB,MAAM,cAAc,CAAC,KAAK,GAAG;AAGpE,SAAO"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { EncoderError } from "./error.js";
|
|
2
|
+
import { createCsvFormatter } from "./csv/csv-formatter.js";
|
|
3
|
+
|
|
4
|
+
//#region src/encoder/csv.ts
|
|
5
|
+
/**
|
|
6
|
+
* CSV encoder - converts CSV strings, arrays of objects, or arrays of arrays to File objects.
|
|
7
|
+
* Uses a simplified CSV formatter without streaming support.
|
|
8
|
+
*/
|
|
9
|
+
var CsvEncoder = class {
|
|
10
|
+
async encode(input, options) {
|
|
11
|
+
try {
|
|
12
|
+
let csvContent;
|
|
13
|
+
if (typeof input === "string") csvContent = input;
|
|
14
|
+
else if (Array.isArray(input)) csvContent = this.#arrayToCsv(input, options?.csv);
|
|
15
|
+
else throw new EncoderError("Invalid CSV input: must be string or array", "INVALID_CSV");
|
|
16
|
+
const blob = new Blob([csvContent], { type: "text/csv" });
|
|
17
|
+
return {
|
|
18
|
+
file: new File([blob], options?.name || "data.csv", { type: "text/csv" }),
|
|
19
|
+
options: options || {}
|
|
20
|
+
};
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (error instanceof EncoderError) throw error;
|
|
23
|
+
if (error instanceof Error) throw new EncoderError(`CSV encoding failed: ${error.message}`, "INVALID_CSV", error);
|
|
24
|
+
throw new EncoderError("CSV encoding failed: unknown error", "INVALID_CSV");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
#arrayToCsv(data, csvOptions) {
|
|
28
|
+
return createCsvFormatter({
|
|
29
|
+
headers: true,
|
|
30
|
+
...csvOptions
|
|
31
|
+
}).format(data);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Encode CSV data to a File object.
|
|
36
|
+
*/
|
|
37
|
+
async function csvToFile(data, options) {
|
|
38
|
+
return new CsvEncoder().encode(data, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { CsvEncoder, csvToFile };
|
|
43
|
+
//# sourceMappingURL=csv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv.js","names":["#arrayToCsv"],"sources":["../../../src/encoder/csv.ts"],"sourcesContent":["import type { Encoder, EncoderResult, UploadOptions } from \"./types\";\nimport { EncoderError } from \"./error\";\nimport {\n createCsvFormatter,\n type CsvFormatterOptions,\n} from \"./csv/csv-formatter\";\n\n/**\n * CSV encoder - converts CSV strings, arrays of objects, or arrays of arrays to File objects.\n * Uses a simplified CSV formatter without streaming support.\n *\n * This implementation is derived from @fast-csv/format (https://github.com/C2FO/fast-csv)\n * Copyright (c) 2011 C2FO Labs, LLC\n * Licensed under the MIT License\n */\n\n/**\n * Extended upload options for CSV encoder.\n * Extends base UploadOptions with CSV formatting options.\n */\nexport interface CsvUploadOptions extends UploadOptions {\n /**\n * CSV formatting options.\n */\n csv?: CsvFormatterOptions;\n}\n\n/**\n * CSV encoder - converts CSV strings, arrays of objects, or arrays of arrays to File objects.\n * Uses a simplified CSV formatter without streaming support.\n */\nexport class CsvEncoder implements Encoder<string | object[] | any[][]> {\n async encode(\n input: string | object[] | any[][],\n options?: CsvUploadOptions,\n ): Promise<EncoderResult> {\n try {\n let csvContent: string;\n\n if (typeof input === \"string\") {\n // Raw CSV string - use as-is\n csvContent = input;\n } else if (Array.isArray(input)) {\n // Convert array to CSV using our formatter\n csvContent = this.#arrayToCsv(input, options?.csv);\n } else {\n throw new EncoderError(\n \"Invalid CSV input: must be string or array\",\n \"INVALID_CSV\",\n );\n }\n\n const blob = new Blob([csvContent], { type: \"text/csv\" });\n const file = new File([blob], options?.name || \"data.csv\", {\n type: \"text/csv\",\n });\n\n return {\n file,\n options: options || {},\n };\n } catch (error) {\n if (error instanceof EncoderError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new EncoderError(\n `CSV encoding failed: ${error.message}`,\n \"INVALID_CSV\",\n error,\n );\n }\n throw new EncoderError(\n \"CSV encoding failed: unknown error\",\n \"INVALID_CSV\",\n );\n }\n }\n\n #arrayToCsv(\n data: any[] | object[][],\n csvOptions?: CsvFormatterOptions,\n ): string {\n const formatter = createCsvFormatter({\n headers: true,\n ...csvOptions,\n });\n\n return formatter.format(data);\n }\n}\n\n/**\n * Encode CSV data to a File object.\n */\nexport async function csvToFile(\n data: string | object[] | any[][],\n options?: CsvUploadOptions,\n): Promise<EncoderResult> {\n const encoder = new CsvEncoder();\n return encoder.encode(data, options);\n}\n"],"mappings":";;;;;;;;AA+BA,IAAa,aAAb,MAAwE;CACtE,MAAM,OACJ,OACA,SACwB;AACxB,MAAI;GACF,IAAI;AAEJ,OAAI,OAAO,UAAU,SAEnB,cAAa;YACJ,MAAM,QAAQ,MAAM,CAE7B,cAAa,MAAKA,WAAY,OAAO,SAAS,IAAI;OAElD,OAAM,IAAI,aACR,8CACA,cACD;GAGH,MAAM,OAAO,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,MAAM,YAAY,CAAC;AAKzD,UAAO;IACL,MALW,IAAI,KAAK,CAAC,KAAK,EAAE,SAAS,QAAQ,YAAY,EACzD,MAAM,YACP,CAAC;IAIA,SAAS,WAAW,EAAE;IACvB;WACM,OAAO;AACd,OAAI,iBAAiB,aACnB,OAAM;AAER,OAAI,iBAAiB,MACnB,OAAM,IAAI,aACR,wBAAwB,MAAM,WAC9B,eACA,MACD;AAEH,SAAM,IAAI,aACR,sCACA,cACD;;;CAIL,YACE,MACA,YACQ;AAMR,SALkB,mBAAmB;GACnC,SAAS;GACT,GAAG;GACJ,CAAC,CAEe,OAAO,KAAK;;;;;;AAOjC,eAAsB,UACpB,MACA,SACwB;AAExB,QADgB,IAAI,YAAY,CACjB,OAAO,MAAM,QAAQ"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/encoder/error.ts
|
|
2
|
+
/**
|
|
3
|
+
* Error wrapper for encoder operations.
|
|
4
|
+
*/
|
|
5
|
+
var EncoderError = class extends Error {
|
|
6
|
+
code;
|
|
7
|
+
cause;
|
|
8
|
+
constructor(message, code, cause) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "EncoderError";
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.cause = cause;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { EncoderError };
|
|
18
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","names":[],"sources":["../../../src/encoder/error.ts"],"sourcesContent":["/**\n * Error wrapper for encoder operations.\n */\nexport class EncoderError extends Error {\n code: \"INVALID_JSON\" | \"INVALID_BASE64\" | \"INVALID_URL\" | \"INVALID_CSV\" | \"INVALID_TEXT\" | \"NETWORK_ERROR\" | \"UNKNOWN\";\n cause?: Error;\n\n constructor(\n message: string,\n code: EncoderError[\"code\"],\n cause?: Error,\n ) {\n super(message);\n this.name = \"EncoderError\";\n this.code = code;\n this.cause = cause;\n }\n}\n"],"mappings":";;;;AAGA,IAAa,eAAb,cAAkC,MAAM;CACtC;CACA;CAEA,YACE,SACA,MACA,OACA;AACA,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,QAAQ"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { EncoderError } from "./error.js";
|
|
2
|
+
import { JsonEncoder, jsonToFile } from "./json.js";
|
|
3
|
+
import { Base64Encoder, base64ToFile } from "./base64.js";
|
|
4
|
+
import { UrlEncoder, urlToFile } from "./url.js";
|
|
5
|
+
import { CsvEncoder, csvToFile } from "./csv.js";
|
|
6
|
+
import { TextEncoder, textToFile } from "./text.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { EncoderError } from "./error.js";
|
|
2
|
+
|
|
3
|
+
//#region src/encoder/json.ts
|
|
4
|
+
/**
|
|
5
|
+
* JSON encoder - converts JSON objects to File objects.
|
|
6
|
+
*/
|
|
7
|
+
var JsonEncoder = class {
|
|
8
|
+
async encode(data, options) {
|
|
9
|
+
try {
|
|
10
|
+
const json = JSON.stringify(data, null, 2);
|
|
11
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
12
|
+
const filename = options?.name || "data.json";
|
|
13
|
+
return {
|
|
14
|
+
file: new File([blob], filename, { type: "application/json" }),
|
|
15
|
+
options: {
|
|
16
|
+
name: options?.name,
|
|
17
|
+
keyvalues: options?.keyvalues
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error instanceof Error) throw new EncoderError(`JSON encoding failed: ${error.message}`, "INVALID_JSON", error);
|
|
22
|
+
throw new EncoderError("JSON encoding failed: unknown error", "INVALID_JSON");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Encode a JSON object to a File object.
|
|
28
|
+
*/
|
|
29
|
+
async function jsonToFile(data, options) {
|
|
30
|
+
return new JsonEncoder().encode(data, options);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { JsonEncoder, jsonToFile };
|
|
35
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","names":[],"sources":["../../../src/encoder/json.ts"],"sourcesContent":["import type { Encoder, EncoderResult, UploadOptions } from \"./types\";\nimport { EncoderError } from \"./error\";\n\n/**\n * JSON encoder - converts JSON objects to File objects.\n */\nexport class JsonEncoder implements Encoder<object> {\n async encode(data: object, options?: UploadOptions): Promise<EncoderResult> {\n try {\n const json = JSON.stringify(data, null, 2);\n const blob = new Blob([json], { type: \"application/json\" });\n const filename = options?.name || \"data.json\";\n const file = new File([blob], filename, { type: \"application/json\" });\n\n return {\n file,\n options: {\n name: options?.name,\n keyvalues: options?.keyvalues,\n },\n };\n } catch (error) {\n if (error instanceof Error) {\n throw new EncoderError(\n `JSON encoding failed: ${error.message}`,\n \"INVALID_JSON\",\n error,\n );\n }\n throw new EncoderError(\n \"JSON encoding failed: unknown error\",\n \"INVALID_JSON\",\n );\n }\n }\n}\n\n/**\n * Encode a JSON object to a File object.\n */\nexport async function jsonToFile(\n data: object,\n options?: UploadOptions,\n): Promise<EncoderResult> {\n const encoder = new JsonEncoder();\n return encoder.encode(data, options);\n}\n"],"mappings":";;;;;;AAMA,IAAa,cAAb,MAAoD;CAClD,MAAM,OAAO,MAAc,SAAiD;AAC1E,MAAI;GACF,MAAM,OAAO,KAAK,UAAU,MAAM,MAAM,EAAE;GAC1C,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,oBAAoB,CAAC;GAC3D,MAAM,WAAW,SAAS,QAAQ;AAGlC,UAAO;IACL,MAHW,IAAI,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;IAInE,SAAS;KACP,MAAM,SAAS;KACf,WAAW,SAAS;KACrB;IACF;WACM,OAAO;AACd,OAAI,iBAAiB,MACnB,OAAM,IAAI,aACR,yBAAyB,MAAM,WAC/B,gBACA,MACD;AAEH,SAAM,IAAI,aACR,uCACA,eACD;;;;;;;AAQP,eAAsB,WACpB,MACA,SACwB;AAExB,QADgB,IAAI,aAAa,CAClB,OAAO,MAAM,QAAQ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { EncoderError } from "./error.js";
|
|
2
|
+
|
|
3
|
+
//#region src/encoder/text.ts
|
|
4
|
+
/**
|
|
5
|
+
* Text encoder - converts text strings to File objects.
|
|
6
|
+
*/
|
|
7
|
+
var TextEncoder = class {
|
|
8
|
+
async encode(data, options) {
|
|
9
|
+
try {
|
|
10
|
+
const blob = new Blob([data], { type: "text/plain" });
|
|
11
|
+
const filename = options?.name || "data.txt";
|
|
12
|
+
return {
|
|
13
|
+
file: new File([blob], filename, { type: "text/plain" }),
|
|
14
|
+
options: {
|
|
15
|
+
name: options?.name,
|
|
16
|
+
keyvalues: options?.keyvalues
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error instanceof Error) throw new EncoderError(`Text encoding failed: ${error.message}`, "INVALID_TEXT", error);
|
|
21
|
+
throw new EncoderError("Text encoding failed: unknown error", "INVALID_TEXT");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Encode a text string to a File object.
|
|
27
|
+
*/
|
|
28
|
+
async function textToFile(data, options) {
|
|
29
|
+
return new TextEncoder().encode(data, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { TextEncoder, textToFile };
|
|
34
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","names":[],"sources":["../../../src/encoder/text.ts"],"sourcesContent":["import type { Encoder, EncoderResult, UploadOptions } from \"./types\";\nimport { EncoderError } from \"./error\";\n\n/**\n * Text encoder - converts text strings to File objects.\n */\nexport class TextEncoder implements Encoder<string> {\n async encode(data: string, options?: UploadOptions): Promise<EncoderResult> {\n try {\n const blob = new Blob([data], { type: \"text/plain\" });\n const filename = options?.name || \"data.txt\";\n const file = new File([blob], filename, { type: \"text/plain\" });\n\n return {\n file,\n options: {\n name: options?.name,\n keyvalues: options?.keyvalues,\n },\n };\n } catch (error) {\n if (error instanceof Error) {\n throw new EncoderError(\n `Text encoding failed: ${error.message}`,\n \"INVALID_TEXT\",\n error,\n );\n }\n throw new EncoderError(\n \"Text encoding failed: unknown error\",\n \"INVALID_TEXT\",\n );\n }\n }\n}\n\n/**\n * Encode a text string to a File object.\n */\nexport async function textToFile(\n data: string,\n options?: UploadOptions,\n): Promise<EncoderResult> {\n const encoder = new TextEncoder();\n return encoder.encode(data, options);\n}\n"],"mappings":";;;;;;AAMA,IAAa,cAAb,MAAoD;CAClD,MAAM,OAAO,MAAc,SAAiD;AAC1E,MAAI;GACF,MAAM,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,cAAc,CAAC;GACrD,MAAM,WAAW,SAAS,QAAQ;AAGlC,UAAO;IACL,MAHW,IAAI,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;IAI7D,SAAS;KACP,MAAM,SAAS;KACf,WAAW,SAAS;KACrB;IACF;WACM,OAAO;AACd,OAAI,iBAAiB,MACnB,OAAM,IAAI,aACR,yBAAyB,MAAM,WAC/B,gBACA,MACD;AAEH,SAAM,IAAI,aACR,uCACA,eACD;;;;;;;AAQP,eAAsB,WACpB,MACA,SACwB;AAExB,QADgB,IAAI,aAAa,CAClB,OAAO,MAAM,QAAQ"}
|