@gjsify/formdata 0.3.13 → 0.3.15
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/lib/esm/file.js +28 -23
- package/lib/esm/form-data-to-blob.js +30 -38
- package/lib/esm/formdata.js +97 -89
- package/lib/esm/index.js +3 -6
- package/package.json +3 -3
package/lib/esm/file.js
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
//#region src/file.ts
|
|
2
|
+
/**
|
|
3
|
+
* File class — extends Blob with name and lastModified.
|
|
4
|
+
* Used by FormData when appending Blob values with a filename.
|
|
5
|
+
*/
|
|
6
|
+
const _name = Symbol("File.name");
|
|
7
|
+
const _lastModified = Symbol("File.lastModified");
|
|
8
|
+
var File = class extends Blob {
|
|
9
|
+
[_name];
|
|
10
|
+
[_lastModified];
|
|
11
|
+
webkitRelativePath = "";
|
|
12
|
+
constructor(fileBits, fileName, options) {
|
|
13
|
+
super(fileBits, options);
|
|
14
|
+
this[_name] = String(fileName);
|
|
15
|
+
this[_lastModified] = options?.lastModified ?? Date.now();
|
|
16
|
+
}
|
|
17
|
+
get name() {
|
|
18
|
+
return this[_name];
|
|
19
|
+
}
|
|
20
|
+
get lastModified() {
|
|
21
|
+
return this[_lastModified];
|
|
22
|
+
}
|
|
23
|
+
get [Symbol.toStringTag]() {
|
|
24
|
+
return "File";
|
|
25
|
+
}
|
|
24
26
|
};
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { File };
|
|
@@ -1,45 +1,37 @@
|
|
|
1
1
|
import { File } from "./file.js";
|
|
2
|
+
|
|
3
|
+
//#region src/form-data-to-blob.ts
|
|
2
4
|
function generateBoundary() {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
let boundary = "----formdata-";
|
|
6
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
7
|
+
for (let i = 0; i < 24; i++) {
|
|
8
|
+
boundary += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
9
|
+
}
|
|
10
|
+
return boundary;
|
|
9
11
|
}
|
|
10
12
|
function escape(str) {
|
|
11
|
-
|
|
13
|
+
return str.replace(/\n/g, "%0A").replace(/\r/g, "%0D").replace(/"/g, "%22");
|
|
12
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts a FormData instance into a Blob with multipart/form-data content type.
|
|
17
|
+
*/
|
|
13
18
|
function formDataToBlob(formData, boundary) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
\r
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
`${prefix}${escape(name)}"; filename="${escape(file.name)}"\r
|
|
30
|
-
Content-Type: ${file.type || "application/octet-stream"}\r
|
|
31
|
-
\r
|
|
32
|
-
`
|
|
33
|
-
);
|
|
34
|
-
chunks.push(file);
|
|
35
|
-
chunks.push("\r\n");
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
chunks.push(`--${boundary}--`);
|
|
39
|
-
return new Blob(chunks, {
|
|
40
|
-
type: `multipart/form-data; boundary=${boundary}`
|
|
41
|
-
});
|
|
19
|
+
boundary = boundary ?? generateBoundary();
|
|
20
|
+
const chunks = [];
|
|
21
|
+
const prefix = `--${boundary}\r\nContent-Disposition: form-data; name="`;
|
|
22
|
+
for (const [name, value] of formData.entries()) {
|
|
23
|
+
if (typeof value === "string") {
|
|
24
|
+
chunks.push(`${prefix}${escape(name)}"\r\n\r\n${value.replace(/\r(?!\n)|(?<!\r)\n/g, "\r\n")}\r\n`);
|
|
25
|
+
} else {
|
|
26
|
+
const file = value instanceof File ? value : new File([value], "blob", { type: value.type });
|
|
27
|
+
chunks.push(`${prefix}${escape(name)}"; filename="${escape(file.name)}"\r\n` + `Content-Type: ${file.type || "application/octet-stream"}\r\n\r\n`);
|
|
28
|
+
chunks.push(file);
|
|
29
|
+
chunks.push("\r\n");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
chunks.push(`--${boundary}--`);
|
|
33
|
+
return new Blob(chunks, { type: `multipart/form-data; boundary=${boundary}` });
|
|
42
34
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
};
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { formDataToBlob };
|
package/lib/esm/formdata.js
CHANGED
|
@@ -1,93 +1,101 @@
|
|
|
1
1
|
import { File } from "./file.js";
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
//#region src/formdata.ts
|
|
4
|
+
/**
|
|
5
|
+
* FormData implementation for GJS.
|
|
6
|
+
* Spec: https://xhr.spec.whatwg.org/#interface-formdata
|
|
7
|
+
*/
|
|
8
|
+
const _entries = Symbol("FormData.entries");
|
|
3
9
|
function normalizeValue(name, value, filename) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
if (typeof value === "string") {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
if (value instanceof Blob && !(value instanceof File)) {
|
|
14
|
+
value = new File([value], filename ?? "blob", { type: value.type });
|
|
15
|
+
}
|
|
16
|
+
if (value instanceof File && filename !== undefined) {
|
|
17
|
+
value = new File([value], filename, {
|
|
18
|
+
type: value.type,
|
|
19
|
+
lastModified: value.lastModified
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
17
23
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
FormData
|
|
24
|
+
var FormData = class {
|
|
25
|
+
[_entries] = [];
|
|
26
|
+
constructor() {}
|
|
27
|
+
append(name, value, filename) {
|
|
28
|
+
this[_entries].push({
|
|
29
|
+
name: String(name),
|
|
30
|
+
value: normalizeValue(name, value, filename)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
delete(name) {
|
|
34
|
+
const n = String(name);
|
|
35
|
+
this[_entries] = this[_entries].filter((e) => e.name !== n);
|
|
36
|
+
}
|
|
37
|
+
get(name) {
|
|
38
|
+
const n = String(name);
|
|
39
|
+
const entry = this[_entries].find((e) => e.name === n);
|
|
40
|
+
return entry ? entry.value : null;
|
|
41
|
+
}
|
|
42
|
+
getAll(name) {
|
|
43
|
+
const n = String(name);
|
|
44
|
+
return this[_entries].filter((e) => e.name === n).map((e) => e.value);
|
|
45
|
+
}
|
|
46
|
+
has(name) {
|
|
47
|
+
const n = String(name);
|
|
48
|
+
return this[_entries].some((e) => e.name === n);
|
|
49
|
+
}
|
|
50
|
+
set(name, value, filename) {
|
|
51
|
+
const n = String(name);
|
|
52
|
+
const normalized = normalizeValue(n, value, filename);
|
|
53
|
+
let found = false;
|
|
54
|
+
this[_entries] = this[_entries].filter((e) => {
|
|
55
|
+
if (e.name === n) {
|
|
56
|
+
if (!found) {
|
|
57
|
+
found = true;
|
|
58
|
+
e.value = normalized;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
if (!found) {
|
|
66
|
+
this[_entries].push({
|
|
67
|
+
name: n,
|
|
68
|
+
value: normalized
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
forEach(callback, thisArg) {
|
|
73
|
+
for (const entry of this[_entries]) {
|
|
74
|
+
callback.call(thisArg, entry.value, entry.name, this);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
*entries() {
|
|
78
|
+
for (const entry of this[_entries]) {
|
|
79
|
+
yield [entry.name, entry.value];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
*keys() {
|
|
83
|
+
for (const entry of this[_entries]) {
|
|
84
|
+
yield entry.name;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
*values() {
|
|
88
|
+
for (const entry of this[_entries]) {
|
|
89
|
+
yield entry.value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
[Symbol.iterator]() {
|
|
93
|
+
return this.entries();
|
|
94
|
+
}
|
|
95
|
+
get [Symbol.toStringTag]() {
|
|
96
|
+
return "FormData";
|
|
97
|
+
}
|
|
93
98
|
};
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
export { FormData };
|
package/lib/esm/index.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { FormData } from "./formdata.js";
|
|
2
1
|
import { File } from "./file.js";
|
|
3
2
|
import { formDataToBlob } from "./form-data-to-blob.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
formDataToBlob
|
|
8
|
-
};
|
|
3
|
+
import { FormData } from "./formdata.js";
|
|
4
|
+
|
|
5
|
+
export { File, FormData, formDataToBlob };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/formdata",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "Web FormData implementation for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"web"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.3.
|
|
37
|
-
"@gjsify/unit": "^0.3.
|
|
36
|
+
"@gjsify/cli": "^0.3.15",
|
|
37
|
+
"@gjsify/unit": "^0.3.15",
|
|
38
38
|
"@types/node": "^25.6.0",
|
|
39
39
|
"typescript": "^6.0.3"
|
|
40
40
|
}
|