@@ -18,6 +18,7 @@ const ObjectCreate = Object.create;
18
18
const ObjectDefineProperty = Object . defineProperty ;
19
19
const ObjectEntries = Object . entries ;
20
20
const ObjectGetOwnPropertyDescriptor = Object . getOwnPropertyDescriptor ;
21
+ const StringCtor = String ;
21
22
const StringFromCharCode = String . fromCharCode ;
22
23
const StringPrototypeCharCodeAt = String . prototype . charCodeAt ;
23
24
const StringPrototypeMatchAll = String . prototype . matchAll ;
@@ -146,10 +147,27 @@ export function ToIntegerIfIntegral(value) {
146
147
return number ;
147
148
}
148
149
150
+ // This convenience function isn't in the spec, but is useful in the polyfill
151
+ // for DRY and better error messages.
152
+ export function RequireString ( value ) {
153
+ if ( Type ( value ) !== 'String' ) {
154
+ // Use String() to ensure that Symbols won't throw
155
+ throw new TypeError ( `expected a string, not ${ StringCtor ( value ) } ` ) ;
156
+ }
157
+ return value ;
158
+ }
159
+
160
+ // This function is an enum in the spec, but it's helpful to make it a
161
+ // function in the polyfill.
162
+ function ToPrimitiveAndRequireString ( value ) {
163
+ value = ToPrimitive ( value , StringCtor ) ;
164
+ return RequireString ( value ) ;
165
+ }
166
+
149
167
const BUILTIN_CASTS = new Map ( [
150
168
[ 'year' , ToIntegerWithTruncation ] ,
151
169
[ 'month' , ToPositiveIntegerWithTruncation ] ,
152
- [ 'monthCode' , ToString ] ,
170
+ [ 'monthCode' , ToPrimitiveAndRequireString ] ,
153
171
[ 'day' , ToPositiveIntegerWithTruncation ] ,
154
172
[ 'hour' , ToIntegerWithTruncation ] ,
155
173
[ 'minute' , ToIntegerWithTruncation ] ,
@@ -167,9 +185,9 @@ const BUILTIN_CASTS = new Map([
167
185
[ 'milliseconds' , ToIntegerIfIntegral ] ,
168
186
[ 'microseconds' , ToIntegerIfIntegral ] ,
169
187
[ 'nanoseconds' , ToIntegerIfIntegral ] ,
170
- [ 'era' , ToString ] ,
188
+ [ 'era' , ToPrimitiveAndRequireString ] ,
171
189
[ 'eraYear' , ToIntegerOrInfinity ] ,
172
- [ 'offset' , ToString ]
190
+ [ 'offset' , ToPrimitiveAndRequireString ]
173
191
] ) ;
174
192
175
193
const BUILTIN_DEFAULTS = new Map ( [
@@ -698,7 +716,7 @@ export function RegulateISOYearMonth(year, month, overflow) {
698
716
699
717
export function ToTemporalDurationRecord ( item ) {
700
718
if ( Type ( item ) !== 'Object' ) {
701
- return ParseTemporalDurationString ( ToString ( item ) ) ;
719
+ return ParseTemporalDurationString ( RequireString ( item ) ) ;
702
720
}
703
721
if ( IsTemporalDuration ( item ) ) {
704
722
return {
@@ -980,7 +998,7 @@ export function ToRelativeTemporalObject(options) {
980
998
} else {
981
999
let tzName , z ;
982
1000
( { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar, tzName, offset, z } =
983
- ParseISODateTime ( ToString ( relativeTo ) ) ) ;
1001
+ ParseISODateTime ( RequireString ( relativeTo ) ) ) ;
984
1002
if ( tzName ) {
985
1003
timeZone = ToTemporalTimeZoneSlotValue ( tzName ) ;
986
1004
if ( z ) {
@@ -1128,7 +1146,7 @@ export function ToTemporalDate(item, options) {
1128
1146
return CalendarDateFromFields ( calendar , fields , options ) ;
1129
1147
}
1130
1148
ToTemporalOverflow ( options ) ; // validate and ignore
1131
- let { year, month, day, calendar, z } = ParseTemporalDateString ( ToString ( item ) ) ;
1149
+ let { year, month, day, calendar, z } = ParseTemporalDateString ( RequireString ( item ) ) ;
1132
1150
if ( z ) throw new RangeError ( 'Z designator not supported for PlainDate' ) ;
1133
1151
if ( ! calendar ) calendar = 'iso8601' ;
1134
1152
if ( ! IsBuiltinCalendar ( calendar ) ) throw new RangeError ( `invalid calendar identifier ${ calendar } ` ) ;
@@ -1202,7 +1220,7 @@ export function ToTemporalDateTime(item, options) {
1202
1220
ToTemporalOverflow ( options ) ; // validate and ignore
1203
1221
let z ;
1204
1222
( { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, calendar, z } =
1205
- ParseTemporalDateTimeString ( ToString ( item ) ) ) ;
1223
+ ParseTemporalDateTimeString ( RequireString ( item ) ) ) ;
1206
1224
if ( z ) throw new RangeError ( 'Z designator not supported for PlainDateTime' ) ;
1207
1225
RejectDateTime ( year , month , day , hour , minute , second , millisecond , microsecond , nanosecond ) ;
1208
1226
if ( ! calendar ) calendar = 'iso8601' ;
@@ -1237,7 +1255,8 @@ export function ToTemporalInstant(item) {
1237
1255
const TemporalInstant = GetIntrinsic ( '%Temporal.Instant%' ) ;
1238
1256
return new TemporalInstant ( GetSlot ( item , EPOCHNANOSECONDS ) ) ;
1239
1257
}
1240
- const ns = ParseTemporalInstant ( ToString ( item ) ) ;
1258
+ item = ToPrimitive ( item , StringCtor ) ;
1259
+ const ns = ParseTemporalInstant ( RequireString ( item ) ) ;
1241
1260
const TemporalInstant = GetIntrinsic ( '%Temporal.Instant%' ) ;
1242
1261
return new TemporalInstant ( ns ) ;
1243
1262
}
@@ -1267,7 +1286,7 @@ export function ToTemporalMonthDay(item, options) {
1267
1286
}
1268
1287
1269
1288
ToTemporalOverflow ( options ) ; // validate and ignore
1270
- let { month, day, referenceISOYear, calendar } = ParseTemporalMonthDayString ( ToString ( item ) ) ;
1289
+ let { month, day, referenceISOYear, calendar } = ParseTemporalMonthDayString ( RequireString ( item ) ) ;
1271
1290
if ( calendar === undefined ) calendar = 'iso8601' ;
1272
1291
if ( ! IsBuiltinCalendar ( calendar ) ) throw new RangeError ( `invalid calendar identifier ${ calendar } ` ) ;
1273
1292
calendar = ASCIILowercase ( calendar ) ;
@@ -1309,7 +1328,7 @@ export function ToTemporalTime(item, overflow = 'constrain') {
1309
1328
overflow
1310
1329
) ) ;
1311
1330
} else {
1312
- ( { hour, minute, second, millisecond, microsecond, nanosecond } = ParseTemporalTimeString ( ToString ( item ) ) ) ;
1331
+ ( { hour, minute, second, millisecond, microsecond, nanosecond } = ParseTemporalTimeString ( RequireString ( item ) ) ) ;
1313
1332
RejectTime ( hour , minute , second , millisecond , microsecond , nanosecond ) ;
1314
1333
}
1315
1334
const TemporalPlainTime = GetIntrinsic ( '%Temporal.PlainTime%' ) ;
@@ -1326,7 +1345,7 @@ export function ToTemporalYearMonth(item, options) {
1326
1345
}
1327
1346
1328
1347
ToTemporalOverflow ( options ) ; // validate and ignore
1329
- let { year, month, referenceISODay, calendar } = ParseTemporalYearMonthString ( ToString ( item ) ) ;
1348
+ let { year, month, referenceISODay, calendar } = ParseTemporalYearMonthString ( RequireString ( item ) ) ;
1330
1349
if ( calendar === undefined ) calendar = 'iso8601' ;
1331
1350
if ( ! IsBuiltinCalendar ( calendar ) ) throw new RangeError ( `invalid calendar identifier ${ calendar } ` ) ;
1332
1351
calendar = ASCIILowercase ( calendar ) ;
@@ -1447,7 +1466,7 @@ export function ToTemporalZonedDateTime(item, options) {
1447
1466
} else {
1448
1467
let tzName , z ;
1449
1468
( { year, month, day, hour, minute, second, millisecond, microsecond, nanosecond, tzName, offset, z, calendar } =
1450
- ParseTemporalZonedDateTimeString ( ToString ( item ) ) ) ;
1469
+ ParseTemporalZonedDateTimeString ( RequireString ( item ) ) ) ;
1451
1470
timeZone = ToTemporalTimeZoneSlotValue ( tzName ) ;
1452
1471
if ( z ) {
1453
1472
offsetBehaviour = 'exact' ;
@@ -1973,7 +1992,7 @@ export function ToTemporalCalendarSlotValue(calendarLike) {
1973
1992
}
1974
1993
return calendarLike ;
1975
1994
}
1976
- const identifier = ToString ( calendarLike ) ;
1995
+ const identifier = RequireString ( calendarLike ) ;
1977
1996
if ( IsBuiltinCalendar ( identifier ) ) return ASCIILowercase ( identifier ) ;
1978
1997
let calendar ;
1979
1998
try {
@@ -2092,7 +2111,7 @@ export function ToTemporalTimeZoneSlotValue(temporalTimeZoneLike) {
2092
2111
}
2093
2112
return temporalTimeZoneLike ;
2094
2113
}
2095
- const identifier = ToString ( temporalTimeZoneLike ) ;
2114
+ const identifier = RequireString ( temporalTimeZoneLike ) ;
2096
2115
const { tzName, offset, z } = ParseTemporalTimeZoneString ( identifier ) ;
2097
2116
if ( tzName ) {
2098
2117
// tzName is any valid identifier string in brackets, and could be an offset identifier
0 commit comments