@etsoo/shared 1.1.83 → 1.1.85
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/README.md +11 -0
- package/__tests__/ContentDisposition.ts +24 -0
- package/lib/cjs/DataTypes.d.ts +19 -0
- package/lib/cjs/DataTypes.js +16 -0
- package/lib/cjs/DomUtils.d.ts +2 -6
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/types/ContentDisposition.d.ts +22 -0
- package/lib/cjs/types/ContentDisposition.js +75 -0
- package/lib/mjs/DataTypes.d.ts +19 -0
- package/lib/mjs/DataTypes.js +16 -0
- package/lib/mjs/DomUtils.d.ts +2 -6
- package/lib/mjs/index.d.ts +1 -0
- package/lib/mjs/index.js +1 -0
- package/lib/mjs/types/ContentDisposition.d.ts +22 -0
- package/lib/mjs/types/ContentDisposition.js +71 -0
- package/package.json +2 -7
- package/src/DataTypes.ts +24 -0
- package/src/index.ts +1 -0
- package/src/types/ContentDisposition.ts +81 -0
package/README.md
CHANGED
|
@@ -32,6 +32,15 @@ $ yarn add @etsoo/shared
|
|
|
32
32
|
## storage
|
|
33
33
|
Storage interface and browser storage implementation
|
|
34
34
|
|
|
35
|
+
## ContentDisposition
|
|
36
|
+
Content disposition of HTTP
|
|
37
|
+
|
|
38
|
+
|Name|Description|
|
|
39
|
+
|---:|---|
|
|
40
|
+
|static parse|Parse header value|
|
|
41
|
+
|Methods||
|
|
42
|
+
|format|Format to standard output|
|
|
43
|
+
|
|
35
44
|
## EColor
|
|
36
45
|
Etsoo implmented Color
|
|
37
46
|
|
|
@@ -121,6 +130,8 @@ Data type definitions and type safe functions. ListItemType and ListItemType1 ar
|
|
|
121
130
|
|MConstructor|Mixins constructor|
|
|
122
131
|
|ObjType|Generic object type|
|
|
123
132
|
|Optional|Make properties optional|
|
|
133
|
+
|PlacementEnum|Placement enum|
|
|
134
|
+
|Placement|Placement type|
|
|
124
135
|
|RequireAtLeastOne|Require at least one property of the keys|
|
|
125
136
|
|Simple|Basic or basic array type|
|
|
126
137
|
|SimpleEnum|Simple type enum|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ContentDisposition } from '../src/types/ContentDisposition';
|
|
2
|
+
|
|
3
|
+
test('Tests for parse', () => {
|
|
4
|
+
const cd1 = ContentDisposition.parse(
|
|
5
|
+
"attachment; filename=__PDF.pdf; filename*=UTF-8''%E6%B5%8B%E8%AF%95PDF.pdf"
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
const cd2 = ContentDisposition.parse(
|
|
9
|
+
`attachment; filename="__PDF.pdf"; filename*="UTF-8''%E6%B5%8B%E8%AF%95PDF.pdf"`
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
expect(cd1?.type).toBe(cd2?.type);
|
|
13
|
+
expect(cd1?.filename).toBe(cd2?.filename);
|
|
14
|
+
expect(cd1?.filename).toBe('测试PDF.pdf');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('Tests for format', () => {
|
|
18
|
+
const cd1 = new ContentDisposition('form-data', 'a-b.jpg', 'file');
|
|
19
|
+
expect(cd1.format()).toBe(`form-data; name="file"; filename="a-b.jpg"`);
|
|
20
|
+
const cd2 = new ContentDisposition('attachment', '测试PDF.pdf');
|
|
21
|
+
expect(cd2.format()).toBe(
|
|
22
|
+
`attachment; filename="__PDF.pdf"; filename*="UTF-8''%E6%B5%8B%E8%AF%95PDF.pdf"`
|
|
23
|
+
);
|
|
24
|
+
});
|
package/lib/cjs/DataTypes.d.ts
CHANGED
|
@@ -114,6 +114,25 @@ export declare namespace DataTypes {
|
|
|
114
114
|
* Vertical align
|
|
115
115
|
*/
|
|
116
116
|
type VAlign = Lowercase<keyof typeof VAlignEnum>;
|
|
117
|
+
/**
|
|
118
|
+
* Placement enum
|
|
119
|
+
*/
|
|
120
|
+
enum PlacementEnum {
|
|
121
|
+
TopLeft = 0,
|
|
122
|
+
TopCenter = 1,
|
|
123
|
+
TopRight = 2,
|
|
124
|
+
MiddleLeft = 3,
|
|
125
|
+
Center = 4,
|
|
126
|
+
MiddleRight = 5,
|
|
127
|
+
BottomLeft = 6,
|
|
128
|
+
BottomCenter = 7,
|
|
129
|
+
BottomRight = 8,
|
|
130
|
+
Unknown = 9
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Placement type
|
|
134
|
+
*/
|
|
135
|
+
type Placement = keyof typeof PlacementEnum;
|
|
117
136
|
/**
|
|
118
137
|
* Number and string combination id type
|
|
119
138
|
*/
|
package/lib/cjs/DataTypes.js
CHANGED
|
@@ -76,6 +76,22 @@ var DataTypes;
|
|
|
76
76
|
VAlignEnum[VAlignEnum["Center"] = 2] = "Center";
|
|
77
77
|
VAlignEnum[VAlignEnum["Bottom"] = 3] = "Bottom";
|
|
78
78
|
})(VAlignEnum = DataTypes.VAlignEnum || (DataTypes.VAlignEnum = {}));
|
|
79
|
+
/**
|
|
80
|
+
* Placement enum
|
|
81
|
+
*/
|
|
82
|
+
let PlacementEnum;
|
|
83
|
+
(function (PlacementEnum) {
|
|
84
|
+
PlacementEnum[PlacementEnum["TopLeft"] = 0] = "TopLeft";
|
|
85
|
+
PlacementEnum[PlacementEnum["TopCenter"] = 1] = "TopCenter";
|
|
86
|
+
PlacementEnum[PlacementEnum["TopRight"] = 2] = "TopRight";
|
|
87
|
+
PlacementEnum[PlacementEnum["MiddleLeft"] = 3] = "MiddleLeft";
|
|
88
|
+
PlacementEnum[PlacementEnum["Center"] = 4] = "Center";
|
|
89
|
+
PlacementEnum[PlacementEnum["MiddleRight"] = 5] = "MiddleRight";
|
|
90
|
+
PlacementEnum[PlacementEnum["BottomLeft"] = 6] = "BottomLeft";
|
|
91
|
+
PlacementEnum[PlacementEnum["BottomCenter"] = 7] = "BottomCenter";
|
|
92
|
+
PlacementEnum[PlacementEnum["BottomRight"] = 8] = "BottomRight";
|
|
93
|
+
PlacementEnum[PlacementEnum["Unknown"] = 9] = "Unknown"; // Reserved for modal, only one instance held at the same time
|
|
94
|
+
})(PlacementEnum = DataTypes.PlacementEnum || (DataTypes.PlacementEnum = {}));
|
|
79
95
|
/**
|
|
80
96
|
* Convert value to target type
|
|
81
97
|
* @param input Input value
|
package/lib/cjs/DomUtils.d.ts
CHANGED
|
@@ -79,16 +79,12 @@ export declare namespace DomUtils {
|
|
|
79
79
|
const getCulture: <T extends DataTypes.StringRecord>(items: Readonly<{
|
|
80
80
|
name: string;
|
|
81
81
|
label: string;
|
|
82
|
-
resources: T;
|
|
83
|
-
* Current detected culture
|
|
84
|
-
*/
|
|
82
|
+
resources: T;
|
|
85
83
|
compatibleNames?: string[] | undefined;
|
|
86
84
|
}>[], culture: string) => [Readonly<{
|
|
87
85
|
name: string;
|
|
88
86
|
label: string;
|
|
89
|
-
resources: T;
|
|
90
|
-
* Current detected culture
|
|
91
|
-
*/
|
|
87
|
+
resources: T;
|
|
92
88
|
compatibleNames?: string[] | undefined;
|
|
93
89
|
}> | undefined, CultureMatch];
|
|
94
90
|
/**
|
package/lib/cjs/index.d.ts
CHANGED
package/lib/cjs/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types/ContentDisposition"), exports);
|
|
17
18
|
__exportStar(require("./types/DelayedExecutorType"), exports);
|
|
18
19
|
__exportStar(require("./types/EColor"), exports);
|
|
19
20
|
__exportStar(require("./types/EHistory"), exports);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content disposition of HTTP
|
|
3
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
|
4
|
+
*/
|
|
5
|
+
export declare class ContentDisposition {
|
|
6
|
+
readonly type: string;
|
|
7
|
+
readonly filename: string;
|
|
8
|
+
readonly name?: string | undefined;
|
|
9
|
+
constructor(type: 'inline' | 'attachment', filename: string);
|
|
10
|
+
constructor(type: 'form-data', filename: string, name: string);
|
|
11
|
+
/**
|
|
12
|
+
* Format to standard output
|
|
13
|
+
* @returns Result
|
|
14
|
+
*/
|
|
15
|
+
format(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse header value
|
|
18
|
+
* @param header Content-Disposition header value
|
|
19
|
+
* @returns Object
|
|
20
|
+
*/
|
|
21
|
+
static parse(header: string | undefined | null): ContentDisposition | undefined;
|
|
22
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContentDisposition = void 0;
|
|
4
|
+
const Utils_1 = require("../Utils");
|
|
5
|
+
/**
|
|
6
|
+
* Content disposition of HTTP
|
|
7
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
|
8
|
+
*/
|
|
9
|
+
class ContentDisposition {
|
|
10
|
+
constructor(type, filename, name) {
|
|
11
|
+
this.type = type;
|
|
12
|
+
this.filename = filename;
|
|
13
|
+
this.name = name;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Format to standard output
|
|
17
|
+
* @returns Result
|
|
18
|
+
*/
|
|
19
|
+
format() {
|
|
20
|
+
const items = [this.type];
|
|
21
|
+
if (this.name)
|
|
22
|
+
items.push(`name="${this.name}"`);
|
|
23
|
+
const filename1 = this.filename.replace(/[^a-zA-Z0-9\.-]/g, '_');
|
|
24
|
+
items.push(`filename="${filename1}"`);
|
|
25
|
+
if (filename1 != this.filename)
|
|
26
|
+
items.push(`filename*="UTF-8''${encodeURIComponent(this.filename)}"`);
|
|
27
|
+
return items.join('; ');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parse header value
|
|
31
|
+
* @param header Content-Disposition header value
|
|
32
|
+
* @returns Object
|
|
33
|
+
*/
|
|
34
|
+
static parse(header) {
|
|
35
|
+
if (!header)
|
|
36
|
+
return undefined;
|
|
37
|
+
const parts = header.trim().split(/\s*;\s*/g);
|
|
38
|
+
const len = parts.length;
|
|
39
|
+
if (len < 2)
|
|
40
|
+
return undefined;
|
|
41
|
+
const type = parts[0];
|
|
42
|
+
let name;
|
|
43
|
+
let filename = '';
|
|
44
|
+
for (let i = 1; i < len; i++) {
|
|
45
|
+
const part = parts[i];
|
|
46
|
+
let [field, value] = part.split(/\s*=\s*/g);
|
|
47
|
+
// case-insensitive
|
|
48
|
+
field = field.toLowerCase();
|
|
49
|
+
// Remove quotes
|
|
50
|
+
value = Utils_1.Utils.trim(value, '"');
|
|
51
|
+
if (field === 'name') {
|
|
52
|
+
name = value;
|
|
53
|
+
}
|
|
54
|
+
else if (field === 'filename') {
|
|
55
|
+
if (filename === '')
|
|
56
|
+
filename = value;
|
|
57
|
+
}
|
|
58
|
+
else if (field === 'filename*') {
|
|
59
|
+
const pos = value.indexOf("''");
|
|
60
|
+
filename =
|
|
61
|
+
pos == -1
|
|
62
|
+
? value
|
|
63
|
+
: decodeURIComponent(value.substring(pos + 2));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (type === 'form-data') {
|
|
67
|
+
return new ContentDisposition(type, filename, name !== null && name !== void 0 ? name : 'file');
|
|
68
|
+
}
|
|
69
|
+
if (type === 'inline' || type === 'attachment') {
|
|
70
|
+
return new ContentDisposition(type, filename);
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.ContentDisposition = ContentDisposition;
|
package/lib/mjs/DataTypes.d.ts
CHANGED
|
@@ -114,6 +114,25 @@ export declare namespace DataTypes {
|
|
|
114
114
|
* Vertical align
|
|
115
115
|
*/
|
|
116
116
|
type VAlign = Lowercase<keyof typeof VAlignEnum>;
|
|
117
|
+
/**
|
|
118
|
+
* Placement enum
|
|
119
|
+
*/
|
|
120
|
+
enum PlacementEnum {
|
|
121
|
+
TopLeft = 0,
|
|
122
|
+
TopCenter = 1,
|
|
123
|
+
TopRight = 2,
|
|
124
|
+
MiddleLeft = 3,
|
|
125
|
+
Center = 4,
|
|
126
|
+
MiddleRight = 5,
|
|
127
|
+
BottomLeft = 6,
|
|
128
|
+
BottomCenter = 7,
|
|
129
|
+
BottomRight = 8,
|
|
130
|
+
Unknown = 9
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Placement type
|
|
134
|
+
*/
|
|
135
|
+
type Placement = keyof typeof PlacementEnum;
|
|
117
136
|
/**
|
|
118
137
|
* Number and string combination id type
|
|
119
138
|
*/
|
package/lib/mjs/DataTypes.js
CHANGED
|
@@ -73,6 +73,22 @@ export var DataTypes;
|
|
|
73
73
|
VAlignEnum[VAlignEnum["Center"] = 2] = "Center";
|
|
74
74
|
VAlignEnum[VAlignEnum["Bottom"] = 3] = "Bottom";
|
|
75
75
|
})(VAlignEnum = DataTypes.VAlignEnum || (DataTypes.VAlignEnum = {}));
|
|
76
|
+
/**
|
|
77
|
+
* Placement enum
|
|
78
|
+
*/
|
|
79
|
+
let PlacementEnum;
|
|
80
|
+
(function (PlacementEnum) {
|
|
81
|
+
PlacementEnum[PlacementEnum["TopLeft"] = 0] = "TopLeft";
|
|
82
|
+
PlacementEnum[PlacementEnum["TopCenter"] = 1] = "TopCenter";
|
|
83
|
+
PlacementEnum[PlacementEnum["TopRight"] = 2] = "TopRight";
|
|
84
|
+
PlacementEnum[PlacementEnum["MiddleLeft"] = 3] = "MiddleLeft";
|
|
85
|
+
PlacementEnum[PlacementEnum["Center"] = 4] = "Center";
|
|
86
|
+
PlacementEnum[PlacementEnum["MiddleRight"] = 5] = "MiddleRight";
|
|
87
|
+
PlacementEnum[PlacementEnum["BottomLeft"] = 6] = "BottomLeft";
|
|
88
|
+
PlacementEnum[PlacementEnum["BottomCenter"] = 7] = "BottomCenter";
|
|
89
|
+
PlacementEnum[PlacementEnum["BottomRight"] = 8] = "BottomRight";
|
|
90
|
+
PlacementEnum[PlacementEnum["Unknown"] = 9] = "Unknown"; // Reserved for modal, only one instance held at the same time
|
|
91
|
+
})(PlacementEnum = DataTypes.PlacementEnum || (DataTypes.PlacementEnum = {}));
|
|
76
92
|
/**
|
|
77
93
|
* Convert value to target type
|
|
78
94
|
* @param input Input value
|
package/lib/mjs/DomUtils.d.ts
CHANGED
|
@@ -79,16 +79,12 @@ export declare namespace DomUtils {
|
|
|
79
79
|
const getCulture: <T extends DataTypes.StringRecord>(items: Readonly<{
|
|
80
80
|
name: string;
|
|
81
81
|
label: string;
|
|
82
|
-
resources: T;
|
|
83
|
-
* Current detected culture
|
|
84
|
-
*/
|
|
82
|
+
resources: T;
|
|
85
83
|
compatibleNames?: string[] | undefined;
|
|
86
84
|
}>[], culture: string) => [Readonly<{
|
|
87
85
|
name: string;
|
|
88
86
|
label: string;
|
|
89
|
-
resources: T;
|
|
90
|
-
* Current detected culture
|
|
91
|
-
*/
|
|
87
|
+
resources: T;
|
|
92
88
|
compatibleNames?: string[] | undefined;
|
|
93
89
|
}> | undefined, CultureMatch];
|
|
94
90
|
/**
|
package/lib/mjs/index.d.ts
CHANGED
package/lib/mjs/index.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content disposition of HTTP
|
|
3
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
|
4
|
+
*/
|
|
5
|
+
export declare class ContentDisposition {
|
|
6
|
+
readonly type: string;
|
|
7
|
+
readonly filename: string;
|
|
8
|
+
readonly name?: string | undefined;
|
|
9
|
+
constructor(type: 'inline' | 'attachment', filename: string);
|
|
10
|
+
constructor(type: 'form-data', filename: string, name: string);
|
|
11
|
+
/**
|
|
12
|
+
* Format to standard output
|
|
13
|
+
* @returns Result
|
|
14
|
+
*/
|
|
15
|
+
format(): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse header value
|
|
18
|
+
* @param header Content-Disposition header value
|
|
19
|
+
* @returns Object
|
|
20
|
+
*/
|
|
21
|
+
static parse(header: string | undefined | null): ContentDisposition | undefined;
|
|
22
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Utils } from '../Utils';
|
|
2
|
+
/**
|
|
3
|
+
* Content disposition of HTTP
|
|
4
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
|
5
|
+
*/
|
|
6
|
+
export class ContentDisposition {
|
|
7
|
+
constructor(type, filename, name) {
|
|
8
|
+
this.type = type;
|
|
9
|
+
this.filename = filename;
|
|
10
|
+
this.name = name;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Format to standard output
|
|
14
|
+
* @returns Result
|
|
15
|
+
*/
|
|
16
|
+
format() {
|
|
17
|
+
const items = [this.type];
|
|
18
|
+
if (this.name)
|
|
19
|
+
items.push(`name="${this.name}"`);
|
|
20
|
+
const filename1 = this.filename.replace(/[^a-zA-Z0-9\.-]/g, '_');
|
|
21
|
+
items.push(`filename="${filename1}"`);
|
|
22
|
+
if (filename1 != this.filename)
|
|
23
|
+
items.push(`filename*="UTF-8''${encodeURIComponent(this.filename)}"`);
|
|
24
|
+
return items.join('; ');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse header value
|
|
28
|
+
* @param header Content-Disposition header value
|
|
29
|
+
* @returns Object
|
|
30
|
+
*/
|
|
31
|
+
static parse(header) {
|
|
32
|
+
if (!header)
|
|
33
|
+
return undefined;
|
|
34
|
+
const parts = header.trim().split(/\s*;\s*/g);
|
|
35
|
+
const len = parts.length;
|
|
36
|
+
if (len < 2)
|
|
37
|
+
return undefined;
|
|
38
|
+
const type = parts[0];
|
|
39
|
+
let name;
|
|
40
|
+
let filename = '';
|
|
41
|
+
for (let i = 1; i < len; i++) {
|
|
42
|
+
const part = parts[i];
|
|
43
|
+
let [field, value] = part.split(/\s*=\s*/g);
|
|
44
|
+
// case-insensitive
|
|
45
|
+
field = field.toLowerCase();
|
|
46
|
+
// Remove quotes
|
|
47
|
+
value = Utils.trim(value, '"');
|
|
48
|
+
if (field === 'name') {
|
|
49
|
+
name = value;
|
|
50
|
+
}
|
|
51
|
+
else if (field === 'filename') {
|
|
52
|
+
if (filename === '')
|
|
53
|
+
filename = value;
|
|
54
|
+
}
|
|
55
|
+
else if (field === 'filename*') {
|
|
56
|
+
const pos = value.indexOf("''");
|
|
57
|
+
filename =
|
|
58
|
+
pos == -1
|
|
59
|
+
? value
|
|
60
|
+
: decodeURIComponent(value.substring(pos + 2));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (type === 'form-data') {
|
|
64
|
+
return new ContentDisposition(type, filename, name !== null && name !== void 0 ? name : 'file');
|
|
65
|
+
}
|
|
66
|
+
if (type === 'inline' || type === 'attachment') {
|
|
67
|
+
return new ContentDisposition(type, filename);
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/shared",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.85",
|
|
4
4
|
"description": "TypeScript shared utilities and functions",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -54,13 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"homepage": "https://github.com/ETSOO/Shared#readme",
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@types/jest": "^29.2.
|
|
57
|
+
"@types/jest": "^29.2.5",
|
|
58
58
|
"@types/lodash.isequal": "^4.5.6",
|
|
59
|
-
"@typescript-eslint/eslint-plugin": "^5.46.1",
|
|
60
|
-
"@typescript-eslint/parser": "^5.46.1",
|
|
61
|
-
"eslint": "^8.30.0",
|
|
62
|
-
"eslint-config-airbnb-base": "^15.0.0",
|
|
63
|
-
"eslint-plugin-import": "^2.26.0",
|
|
64
59
|
"jest": "^29.3.1",
|
|
65
60
|
"jest-environment-jsdom": "^29.3.1",
|
|
66
61
|
"ts-jest": "^29.0.3",
|
package/src/DataTypes.ts
CHANGED
|
@@ -148,6 +148,30 @@ export namespace DataTypes {
|
|
|
148
148
|
*/
|
|
149
149
|
export type VAlign = Lowercase<keyof typeof VAlignEnum>;
|
|
150
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Placement enum
|
|
153
|
+
*/
|
|
154
|
+
export enum PlacementEnum {
|
|
155
|
+
TopLeft,
|
|
156
|
+
TopCenter,
|
|
157
|
+
TopRight,
|
|
158
|
+
|
|
159
|
+
MiddleLeft,
|
|
160
|
+
Center,
|
|
161
|
+
MiddleRight,
|
|
162
|
+
|
|
163
|
+
BottomLeft,
|
|
164
|
+
BottomCenter,
|
|
165
|
+
BottomRight,
|
|
166
|
+
|
|
167
|
+
Unknown // Reserved for modal, only one instance held at the same time
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Placement type
|
|
172
|
+
*/
|
|
173
|
+
export type Placement = keyof typeof PlacementEnum;
|
|
174
|
+
|
|
151
175
|
/**
|
|
152
176
|
* Number and string combination id type
|
|
153
177
|
*/
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Utils } from '../Utils';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Content disposition of HTTP
|
|
5
|
+
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
|
|
6
|
+
*/
|
|
7
|
+
export class ContentDisposition {
|
|
8
|
+
constructor(type: 'inline' | 'attachment', filename: string);
|
|
9
|
+
constructor(type: 'form-data', filename: string, name: string);
|
|
10
|
+
constructor(
|
|
11
|
+
public readonly type: string,
|
|
12
|
+
public readonly filename: string,
|
|
13
|
+
public readonly name?: string
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Format to standard output
|
|
18
|
+
* @returns Result
|
|
19
|
+
*/
|
|
20
|
+
format() {
|
|
21
|
+
const items = [this.type];
|
|
22
|
+
if (this.name) items.push(`name="${this.name}"`);
|
|
23
|
+
const filename1 = this.filename.replace(/[^a-zA-Z0-9\.-]/g, '_');
|
|
24
|
+
items.push(`filename="${filename1}"`);
|
|
25
|
+
if (filename1 != this.filename)
|
|
26
|
+
items.push(
|
|
27
|
+
`filename*="UTF-8''${encodeURIComponent(this.filename)}"`
|
|
28
|
+
);
|
|
29
|
+
return items.join('; ');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse header value
|
|
34
|
+
* @param header Content-Disposition header value
|
|
35
|
+
* @returns Object
|
|
36
|
+
*/
|
|
37
|
+
static parse(header: string | undefined | null) {
|
|
38
|
+
if (!header) return undefined;
|
|
39
|
+
|
|
40
|
+
const parts = header.trim().split(/\s*;\s*/g);
|
|
41
|
+
const len = parts.length;
|
|
42
|
+
if (len < 2) return undefined;
|
|
43
|
+
|
|
44
|
+
const type = parts[0];
|
|
45
|
+
let name: string | undefined;
|
|
46
|
+
let filename: string = '';
|
|
47
|
+
|
|
48
|
+
for (let i = 1; i < len; i++) {
|
|
49
|
+
const part = parts[i];
|
|
50
|
+
let [field, value] = part.split(/\s*=\s*/g);
|
|
51
|
+
|
|
52
|
+
// case-insensitive
|
|
53
|
+
field = field.toLowerCase();
|
|
54
|
+
|
|
55
|
+
// Remove quotes
|
|
56
|
+
value = Utils.trim(value, '"');
|
|
57
|
+
|
|
58
|
+
if (field === 'name') {
|
|
59
|
+
name = value;
|
|
60
|
+
} else if (field === 'filename') {
|
|
61
|
+
if (filename === '') filename = value;
|
|
62
|
+
} else if (field === 'filename*') {
|
|
63
|
+
const pos = value.indexOf("''");
|
|
64
|
+
filename =
|
|
65
|
+
pos == -1
|
|
66
|
+
? value
|
|
67
|
+
: decodeURIComponent(value.substring(pos + 2));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (type === 'form-data') {
|
|
72
|
+
return new ContentDisposition(type, filename, name ?? 'file');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (type === 'inline' || type === 'attachment') {
|
|
76
|
+
return new ContentDisposition(type, filename);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|