-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(@formatjs/intl-durationformat): implement stage-3 spec
part of #4257
- Loading branch information
Long Ho
committed
Nov 13, 2023
1 parent
cb96395
commit 01bcfc7
Showing
22 changed files
with
975 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1 @@ | ||
import { | ||
CanonicalizeLocaleList, | ||
GetOption, | ||
ToObject, | ||
} from '@formatjs/ecma402-abstract' | ||
import {ResolveLocale} from '@formatjs/intl-localematcher' | ||
export interface DurationFormatOptions { | ||
style: 'long' | 'short' | 'narrow' | 'digital' | ||
smallestUnit: 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year' | ||
largestUnit: 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year' | ||
hideZeroValues: | ||
| 'all' | ||
| 'leadingAndTrailing' | ||
| 'leadingOnly' | ||
| 'trailingOnly' | ||
| 'none' | ||
numberingSystem: string | ||
round: boolean | ||
} | ||
|
||
export class DurationFormat { | ||
constructor(locales?: string | string[], options?: DurationFormatOptions) { | ||
// test262/test/intl402/ListFormat/constructor/constructor/newtarget-undefined.js | ||
// Cannot use `new.target` bc of IE11 & TS transpiles it to something else | ||
const newTarget = | ||
this && this instanceof DurationFormat ? this.constructor : void 0 | ||
if (!newTarget) { | ||
throw new TypeError("Intl.DurationFormat must be called with 'new'") | ||
} | ||
const requestedLocales = CanonicalizeLocaleList(locales) | ||
const opt: any = Object.create(null) | ||
const opts = options === undefined ? Object.create(null) : ToObject(options) | ||
const matcher = GetOption( | ||
opts, | ||
'localeMatcher', | ||
'string', | ||
['best fit', 'lookup'], | ||
'best fit' | ||
) | ||
opt.localeMatcher = matcher | ||
// const numberingSystem = GetOption( | ||
// opts, | ||
// 'numberingSystem', | ||
// 'string', | ||
// undefined, | ||
// undefined | ||
// ); | ||
// @ts-expect-error TODO | ||
const {localeData} = DurationFormat | ||
const r = ResolveLocale( | ||
localeData.availableLocales, | ||
requestedLocales, | ||
opt, | ||
// [[RelevantExtensionKeys]] slot, which is a constant | ||
['nu'], | ||
localeData, | ||
DurationFormat.getDefaultLocale | ||
) | ||
console.log('TODO', r) | ||
} | ||
static __defaultLocale: string | ||
static getDefaultLocale() { | ||
return DurationFormat.__defaultLocale | ||
} | ||
} | ||
export * from './src/core' |
14 changes: 14 additions & 0 deletions
14
packages/intl-durationformat/src/abstract/DurationRecordSign.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import {TABLE_1} from '../constants' | ||
import {DurationRecord} from '../types' | ||
|
||
export function DurationRecordSign(record: DurationRecord): -1 | 0 | 1 { | ||
for (const key of TABLE_1) { | ||
if (record[key] < 0) { | ||
return -1 | ||
} | ||
if (record[key] > 0) { | ||
return 1 | ||
} | ||
} | ||
return 0 | ||
} |
59 changes: 59 additions & 0 deletions
59
packages/intl-durationformat/src/abstract/GetDurationUnitOptions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import {GetOption} from '@formatjs/ecma402-abstract' | ||
|
||
export function GetDurationUnitOptions<T extends object>( | ||
unit: keyof T, | ||
options: T, | ||
baseStyle: Exclude<T[keyof T], undefined>, | ||
stylesList: readonly T[keyof T][], | ||
digitalBase: Exclude<T[keyof T], undefined>, | ||
prevStyle: string | ||
) { | ||
let style = GetOption(options, unit, 'string', stylesList, undefined) | ||
let displayDefault = 'always' | ||
if (style === undefined) { | ||
if (baseStyle === 'digital') { | ||
if (unit !== 'hours' && unit !== 'minutes' && unit !== 'seconds') { | ||
displayDefault = 'auto' | ||
} | ||
style = digitalBase | ||
} else { | ||
displayDefault = 'auto' | ||
if (prevStyle === 'numeric' || prevStyle === '2-digit') { | ||
style = 'numeric' as Exclude<T[keyof T], undefined> | ||
} else { | ||
style = baseStyle | ||
} | ||
} | ||
} | ||
let displayField = `${unit as string}Display` as keyof T | ||
let display = GetOption( | ||
options, | ||
displayField, | ||
'string', | ||
['always', 'auto'] as Array<T[keyof T]>, | ||
displayDefault | ||
) | ||
|
||
if (prevStyle === 'numeric' || prevStyle === '2-digit') { | ||
if (style !== 'numeric' && style !== '2-digit') { | ||
throw new RangeError("Can't mix numeric and non-numeric styles") | ||
} else if (unit === 'minutes' || unit === 'seconds') { | ||
style = '2-digit' as Exclude<T[keyof T], undefined> | ||
} | ||
if ( | ||
style === 'numeric' && | ||
display === 'always' && | ||
(unit === 'milliseconds' || | ||
unit === 'microseconds' || | ||
unit === 'nanoseconds') | ||
) { | ||
throw new RangeError( | ||
"Can't display milliseconds, microseconds, or nanoseconds in numeric format" | ||
) | ||
} | ||
} | ||
return { | ||
style, | ||
display, | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
packages/intl-durationformat/src/abstract/IsValidDurationRecord.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import {invariant} from '@formatjs/ecma402-abstract' | ||
import {TABLE_1} from '../constants' | ||
import {DurationRecord} from '../types' | ||
import {DurationRecordSign} from './DurationRecordSign' | ||
|
||
export function IsValidDurationRecord(record: DurationRecord): boolean { | ||
const sign = DurationRecordSign(record) | ||
for (const key of TABLE_1) { | ||
const v = record[key] | ||
invariant(isFinite(Number(v)), `${key} is not finite`) | ||
if (v < 0 && sign > 0) { | ||
return false | ||
} | ||
if (v > 0 && sign < 0) { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
Oops, something went wrong.