happy-dom 10.0.7 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of happy-dom might be problematic. Click here for more details.
- package/cjs/nodes/html-input-element/HTMLInputDateUtility.cjs +24 -0
- package/cjs/nodes/html-input-element/HTMLInputDateUtility.cjs.map +1 -0
- package/cjs/nodes/html-input-element/HTMLInputDateUtility.d.ts +8 -0
- package/cjs/nodes/html-input-element/HTMLInputDateUtility.d.ts.map +1 -0
- package/cjs/nodes/html-input-element/HTMLInputElement.cjs +98 -1
- package/cjs/nodes/html-input-element/HTMLInputElement.cjs.map +1 -1
- package/cjs/nodes/html-input-element/HTMLInputElement.d.ts +6 -0
- package/cjs/nodes/html-input-element/HTMLInputElement.d.ts.map +1 -1
- package/cjs/nodes/html-input-element/HTMLInputElementValueSanitizer.cjs +151 -1
- package/cjs/nodes/html-input-element/HTMLInputElementValueSanitizer.cjs.map +1 -1
- package/cjs/nodes/html-input-element/HTMLInputElementValueSanitizer.d.ts +32 -0
- package/cjs/nodes/html-input-element/HTMLInputElementValueSanitizer.d.ts.map +1 -1
- package/lib/nodes/html-input-element/HTMLInputDateUtility.d.ts +8 -0
- package/lib/nodes/html-input-element/HTMLInputDateUtility.d.ts.map +1 -0
- package/lib/nodes/html-input-element/HTMLInputDateUtility.js +20 -0
- package/lib/nodes/html-input-element/HTMLInputDateUtility.js.map +1 -0
- package/lib/nodes/html-input-element/HTMLInputElement.d.ts +6 -0
- package/lib/nodes/html-input-element/HTMLInputElement.d.ts.map +1 -1
- package/lib/nodes/html-input-element/HTMLInputElement.js +98 -1
- package/lib/nodes/html-input-element/HTMLInputElement.js.map +1 -1
- package/lib/nodes/html-input-element/HTMLInputElementValueSanitizer.d.ts +32 -0
- package/lib/nodes/html-input-element/HTMLInputElementValueSanitizer.d.ts.map +1 -1
- package/lib/nodes/html-input-element/HTMLInputElementValueSanitizer.js +153 -2
- package/lib/nodes/html-input-element/HTMLInputElementValueSanitizer.js.map +1 -1
- package/package.json +1 -1
- package/src/nodes/html-input-element/HTMLInputDateUtility.ts +21 -0
- package/src/nodes/html-input-element/HTMLInputElement.ts +99 -1
- package/src/nodes/html-input-element/HTMLInputElementValueSanitizer.ts +153 -1
@@ -1,6 +1,7 @@
|
|
1
1
|
import HTMLInputElement from './HTMLInputElement.js';
|
2
2
|
|
3
3
|
const NEW_LINES_REGEXP = /[\n\r]/gm;
|
4
|
+
const parseInts = (a: string[]): number[] => a.map((v) => parseInt(v, 10));
|
4
5
|
|
5
6
|
/**
|
6
7
|
* HTML input element value sanitizer.
|
@@ -35,7 +36,7 @@ export default class HTMLInputElementValueSanitizer {
|
|
35
36
|
case 'number':
|
36
37
|
// https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):value-sanitization-algorithm
|
37
38
|
return !isNaN(Number.parseFloat(value)) ? value : '';
|
38
|
-
case 'range':
|
39
|
+
case 'range': {
|
39
40
|
// https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range):value-sanitization-algorithm
|
40
41
|
const number = Number.parseFloat(value);
|
41
42
|
const min = parseFloat(input.min) || 0;
|
@@ -50,11 +51,162 @@ export default class HTMLInputElementValueSanitizer {
|
|
50
51
|
}
|
51
52
|
|
52
53
|
return value;
|
54
|
+
}
|
53
55
|
case 'url':
|
54
56
|
// https://html.spec.whatwg.org/multipage/forms.html#url-state-(type=url):value-sanitization-algorithm
|
55
57
|
return value.trim().replace(NEW_LINES_REGEXP, '');
|
58
|
+
case 'date':
|
59
|
+
// https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date):value-sanitization-algorithm
|
60
|
+
value = this.sanitizeDate(value);
|
61
|
+
return value && this.checkBoundaries(value, input.min, input.max) ? value : '';
|
62
|
+
case 'datetime-local': {
|
63
|
+
// https://html.spec.whatwg.org/multipage/input.html#local-date-and-time-state-(type=datetime-local):value-sanitization-algorithm
|
64
|
+
const match = value.match(
|
65
|
+
/^(\d\d\d\d)-(\d\d)-(\d\d)[T ](\d\d):(\d\d)(?::(\d\d)(?:\.(\d{1,3}))?)?$/
|
66
|
+
);
|
67
|
+
if (!match) {
|
68
|
+
return '';
|
69
|
+
}
|
70
|
+
const dateString = this.sanitizeDate(value.slice(0, 10));
|
71
|
+
let timeString = this.sanitizeTime(value.slice(11));
|
72
|
+
if (!(dateString && timeString)) {
|
73
|
+
return '';
|
74
|
+
}
|
75
|
+
// Has seconds so needs to remove trailing zeros
|
76
|
+
if (match[6] !== undefined) {
|
77
|
+
if (timeString.indexOf('.') !== -1) {
|
78
|
+
// Remove unecessary zeros milliseconds
|
79
|
+
timeString = timeString.replace(/(?:\.0*|(\.\d+?)0+)$/, '$1');
|
80
|
+
}
|
81
|
+
timeString = timeString.replace(/(\d\d:\d\d)(:00)$/, '$1');
|
82
|
+
}
|
83
|
+
return dateString + 'T' + timeString;
|
84
|
+
}
|
85
|
+
case 'month':
|
86
|
+
// https://html.spec.whatwg.org/multipage/input.html#month-state-(type=month):value-sanitization-algorithm
|
87
|
+
if (!(value.match(/^(\d\d\d\d)-(\d\d)$/) && this.parseMonthComponent(value))) {
|
88
|
+
return '';
|
89
|
+
}
|
90
|
+
return this.checkBoundaries(value, input.min, input.max) ? value : '';
|
91
|
+
case 'time': {
|
92
|
+
// https://html.spec.whatwg.org/multipage/input.html#time-state-(type=time):value-sanitization-algorithm
|
93
|
+
value = this.sanitizeTime(value);
|
94
|
+
return value && this.checkBoundaries(value, input.min, input.max) ? value : '';
|
95
|
+
}
|
96
|
+
case 'week': {
|
97
|
+
// https://html.spec.whatwg.org/multipage/input.html#week-state-(type=week):value-sanitization-algorithm
|
98
|
+
const match = value.match(/^(\d\d\d\d)-W(\d\d)$/);
|
99
|
+
if (!match) {
|
100
|
+
return '';
|
101
|
+
}
|
102
|
+
const [intY, intW] = parseInts(match.slice(1, 3));
|
103
|
+
if (intY <= 0 || intW < 1 || intW > 53) {
|
104
|
+
return '';
|
105
|
+
}
|
106
|
+
// Check date is valid
|
107
|
+
const lastWeek = this.lastIsoWeekOfYear(intY);
|
108
|
+
if (intW < 1 || intW > 52 + lastWeek) {
|
109
|
+
return '';
|
110
|
+
}
|
111
|
+
if (!this.checkBoundaries(value, input.min, input.max)) {
|
112
|
+
return '';
|
113
|
+
}
|
114
|
+
return value;
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
return value;
|
119
|
+
}
|
120
|
+
/**
|
121
|
+
* Checks if a value is within the boundaries of min and max.
|
122
|
+
*
|
123
|
+
* @param value
|
124
|
+
* @param min
|
125
|
+
* @param max
|
126
|
+
*/
|
127
|
+
private static checkBoundaries<T>(value: T, min: T, max: T): boolean {
|
128
|
+
if (min && min > value) {
|
129
|
+
return false;
|
130
|
+
} else if (max && max < value) {
|
131
|
+
return false;
|
132
|
+
}
|
133
|
+
return true;
|
134
|
+
}
|
135
|
+
/**
|
136
|
+
* Parses the month component of a date string.
|
137
|
+
*
|
138
|
+
* @param value
|
139
|
+
*/
|
140
|
+
private static parseMonthComponent(value: string): string {
|
141
|
+
const [Y, M] = value.split('-');
|
142
|
+
const [intY, intM] = parseInts([Y, M]);
|
143
|
+
if (isNaN(intY) || isNaN(intM) || intY <= 0 || intM < 1 || intM > 12) {
|
144
|
+
return '';
|
56
145
|
}
|
146
|
+
return value;
|
147
|
+
}
|
148
|
+
/**
|
149
|
+
* Returns the last ISO week of a year.
|
150
|
+
*
|
151
|
+
* @param year
|
152
|
+
*/
|
153
|
+
private static lastIsoWeekOfYear = (year: string | number): number => {
|
154
|
+
const date = new Date(+year, 11, 31);
|
155
|
+
const day = (date.getDay() + 6) % 7;
|
156
|
+
date.setDate(date.getDate() - day + 3);
|
157
|
+
const firstThursday = date.getTime();
|
158
|
+
date.setMonth(0, 1);
|
159
|
+
if (date.getDay() !== 4) {
|
160
|
+
date.setMonth(0, 1 + ((4 - date.getDay() + 7) % 7));
|
161
|
+
}
|
162
|
+
return 1 + Math.ceil((firstThursday - date.getTime()) / 604800000);
|
163
|
+
};
|
57
164
|
|
165
|
+
/**
|
166
|
+
* Sanitizes a date string.
|
167
|
+
*
|
168
|
+
* @param value
|
169
|
+
*/
|
170
|
+
private static sanitizeDate(value: string): string {
|
171
|
+
const match = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
172
|
+
if (!match) {
|
173
|
+
return '';
|
174
|
+
}
|
175
|
+
const month = this.parseMonthComponent(value.slice(0, 7));
|
176
|
+
if (!month) {
|
177
|
+
return '';
|
178
|
+
}
|
179
|
+
const [intY, intM, intD] = parseInts(match.slice(1, 4));
|
180
|
+
if (intD < 1 || intD > 31) {
|
181
|
+
return '';
|
182
|
+
}
|
183
|
+
// Check date is valid
|
184
|
+
const lastDayOfMonth = new Date(intY, intM, 0).getDate();
|
185
|
+
if (intD > lastDayOfMonth) {
|
186
|
+
return '';
|
187
|
+
}
|
58
188
|
return value;
|
59
189
|
}
|
190
|
+
|
191
|
+
/**
|
192
|
+
* Sanitizes a time string.
|
193
|
+
*
|
194
|
+
* @param value
|
195
|
+
*/
|
196
|
+
private static sanitizeTime(value: string): string {
|
197
|
+
const match = value.match(/^(\d{2}):(\d{2})(?::(\d{2}(?:\.(\d{1,3}))?))?$/);
|
198
|
+
if (!match) {
|
199
|
+
return '';
|
200
|
+
}
|
201
|
+
const [intH, intM] = parseInts(match.slice(1, 3));
|
202
|
+
const ms = parseFloat(match[3] || '0') * 1000;
|
203
|
+
if (intH > 23 || intM > 59 || ms > 59999) {
|
204
|
+
return '';
|
205
|
+
}
|
206
|
+
if (ms === 0) {
|
207
|
+
return `${match[1]}:${match[2]}`;
|
208
|
+
} else {
|
209
|
+
return `${match[1]}:${match[2]}${ms >= 10000 ? `:${ms / 1000}` : `:0${ms / 1000}`}`;
|
210
|
+
}
|
211
|
+
}
|
60
212
|
}
|