Skip to content

Commit 914b73e

Browse files
committed
Update test262, add fixes for most new tests
1 parent 77e63d5 commit 914b73e

2 files changed

Lines changed: 133 additions & 27 deletions

File tree

src/factory.ts

Lines changed: 132 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,6 @@ function canonicalizeLocaleList(
3434
return Object.keys(res)
3535
}
3636

37-
function getType(opt: unknown) {
38-
const type =
39-
// @ts-expect-error
40-
opt && Object.prototype.hasOwnProperty.call(opt, 'type') && opt.type
41-
if (!type) return 'cardinal'
42-
if (type === 'cardinal' || type === 'ordinal') return type
43-
throw new RangeError('Not a valid plural type: ' + JSON.stringify(type))
44-
}
45-
4637
function toNumber(value: unknown) {
4738
switch (typeof value) {
4839
case 'number':
@@ -59,18 +50,8 @@ export type Selector = (n: number | string, ord?: boolean) => Category
5950
export type RangeSelector = (start: Category, end: Category) => Category
6051
export type PluralRuleType = 'cardinal' | 'ordinal'
6152

62-
export interface PluralRulesOptions {
63-
localeMatcher?: 'lookup' | 'best fit' | undefined
64-
type?: PluralRuleType | undefined
65-
minimumIntegerDigits?: number | undefined
66-
minimumFractionDigits?: number | undefined
67-
maximumFractionDigits?: number | undefined
68-
minimumSignificantDigits?: number | undefined
69-
maximumSignificantDigits?: number | undefined
70-
roundingPriority?: 'auto' | 'morePrecision' | 'lessPrecision'
71-
}
72-
7353
export interface ResolvedPluralRulesOptions {
54+
compactDisplay?: 'short' | 'long'
7455
locale: string
7556
pluralCategories: Category[]
7657
type: PluralRuleType
@@ -79,7 +60,117 @@ export interface ResolvedPluralRulesOptions {
7960
maximumFractionDigits?: number
8061
minimumSignificantDigits?: number
8162
maximumSignificantDigits?: number
63+
notation: 'standard' | 'scientific' | 'engineering' | 'compact'
64+
roundingIncrement:
65+
| 1
66+
| 2
67+
| 5
68+
| 10
69+
| 20
70+
| 25
71+
| 50
72+
| 100
73+
| 200
74+
| 250
75+
| 500
76+
| 1000
77+
| 2000
78+
| 2500
79+
| 5000
80+
roundingMode:
81+
| 'ceil'
82+
| 'floor'
83+
| 'expand'
84+
| 'trunc'
85+
| 'halfCeil'
86+
| 'halfFloor'
87+
| 'halfExpand'
88+
| 'halfTrunc'
89+
| 'halfEven'
8290
roundingPriority: 'auto' | 'morePrecision' | 'lessPrecision'
91+
trailingZeroDisplay: 'auto' | 'stripIfInteger'
92+
}
93+
94+
export type PluralRulesOptions = Partial<
95+
Omit<ResolvedPluralRulesOptions, 'pluralCategories'>
96+
>
97+
98+
function readOptions(opt: PluralRulesOptions | undefined) {
99+
if (!opt)
100+
return {
101+
type: 'cardinal',
102+
compactDisplay: 'short',
103+
nfOpt: undefined
104+
} as const
105+
106+
const get = <T extends string>(name: string, values: T[]): T => {
107+
const val = Object.prototype.hasOwnProperty.call(opt, name)
108+
? (opt as Record<string, unknown>)[name]
109+
: undefined
110+
if (val === undefined) return values[0]
111+
if (typeof val === 'symbol')
112+
throw new TypeError(`Unsupported symbol as ${name} option value`)
113+
const strval = String(val) as T
114+
if (!values || values.includes(strval)) return strval
115+
throw new RangeError(`Unsupported ${name} option value: ${strval}`)
116+
}
117+
118+
const localeMatcher = get('localeMatcher', ['best fit', 'lookup'])
119+
const type = get('type', ['cardinal', 'ordinal'])
120+
const notation = get('notation', [
121+
'standard',
122+
'scientific',
123+
'engineering',
124+
'compact'
125+
])
126+
const compactDisplay = get('compactDisplay', ['short', 'long'])
127+
const {
128+
minimumIntegerDigits,
129+
minimumFractionDigits,
130+
maximumFractionDigits,
131+
minimumSignificantDigits,
132+
maximumSignificantDigits,
133+
roundingIncrement
134+
} = opt
135+
const roundingMode = get('roundingMode', [
136+
'halfExpand',
137+
'ceil',
138+
'floor',
139+
'expand',
140+
'trunc',
141+
'halfCeil',
142+
'halfFloor',
143+
'halfTrunc',
144+
'halfEven'
145+
])
146+
const roundingPriority = get('roundingPriority', [
147+
'auto',
148+
'morePrecision',
149+
'lessPrecision'
150+
])
151+
const trailingZeroDisplay = get('trailingZeroDisplay', [
152+
'auto',
153+
'stripIfInteger'
154+
])
155+
156+
return {
157+
type,
158+
compactDisplay,
159+
nfOpt: {
160+
localeMatcher,
161+
notation,
162+
compactDisplay: 'short',
163+
minimumIntegerDigits,
164+
minimumFractionDigits,
165+
maximumFractionDigits,
166+
minimumSignificantDigits,
167+
maximumSignificantDigits,
168+
roundingIncrement,
169+
roundingMode,
170+
roundingPriority,
171+
trailingZeroDisplay
172+
}
173+
} as const
83174
}
84175

85176
export interface PluralRules {
@@ -134,6 +225,7 @@ export default function getPluralRules(
134225
#range: RangeSelector
135226
#select: Selector
136227
#type: 'cardinal' | 'ordinal'
228+
#compactDisplay: 'short' | 'long'
137229
#nf: Intl.NumberFormat
138230

139231
constructor(
@@ -145,8 +237,10 @@ export default function getPluralRules(
145237
if (!this.#select)
146238
throw new Error(`Selector not found for locale: ${this.#locale}`)
147239
this.#range = getRangeSelector(this.#locale)
148-
this.#type = getType(opt)
149-
this.#nf = new NumberFormat('en', opt) // make-plural expects latin digits with . decimal separator
240+
const res = readOptions(opt)
241+
this.#nf = new NumberFormat('en', res.nfOpt) // make-plural expects latin digits with . decimal separator
242+
this.#type = res.type
243+
this.#compactDisplay = res.compactDisplay
150244
}
151245

152246
resolvedOptions(): ResolvedPluralRulesOptions {
@@ -156,18 +250,27 @@ export default function getPluralRules(
156250
maximumFractionDigits,
157251
minimumSignificantDigits,
158252
maximumSignificantDigits,
159-
roundingPriority
253+
notation,
254+
roundingIncrement,
255+
roundingMode,
256+
roundingPriority,
257+
trailingZeroDisplay
160258
} = this.#nf.resolvedOptions()
161259
const locale = this.#locale
162260
const type = this.#type
163261
return Object.assign(
164-
{ locale, type, minimumIntegerDigits },
262+
{ locale, type, notation },
263+
notation === 'compact' && { compactDisplay: this.#compactDisplay },
264+
{ minimumIntegerDigits },
165265
typeof minimumSignificantDigits === 'number'
166266
? { minimumSignificantDigits, maximumSignificantDigits }
167267
: { minimumFractionDigits, maximumFractionDigits },
168268
{
169269
pluralCategories: getCategories(locale, type === 'ordinal').slice(0),
170-
roundingPriority: roundingPriority ?? 'auto'
270+
roundingIncrement: roundingIncrement ?? 1,
271+
roundingMode: roundingMode ?? 'halfExpand',
272+
roundingPriority: roundingPriority ?? 'auto',
273+
trailingZeroDisplay: trailingZeroDisplay ?? 'auto'
171274
}
172275
)
173276
}
@@ -177,7 +280,10 @@ export default function getPluralRules(
177280
throw new TypeError(`select() called on incompatible ${this}`)
178281
if (typeof number !== 'number') number = Number(number)
179282
if (!isFinite(number)) return 'other'
180-
const fmt = this.#nf.format(Math.abs(number))
283+
let fmt = ''
284+
for (const part of this.#nf.formatToParts(Math.abs(number))) {
285+
fmt += part.value
286+
}
181287
return this.#select(fmt, this.#type === 'ordinal')
182288
}
183289

test262

Submodule test262 updated 20484 files

0 commit comments

Comments
 (0)