refactor(facade): cleanup Intl facade
This commit is contained in:
parent
7c16ef942e
commit
7b8dae19af
|
@ -8,13 +8,12 @@
|
||||||
|
|
||||||
import {DatePipe} from '@angular/common';
|
import {DatePipe} from '@angular/common';
|
||||||
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
import {PipeResolver} from '@angular/compiler/src/pipe_resolver';
|
||||||
import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
|
||||||
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
|
import {browserDetection} from '@angular/platform-browser/testing/browser_util';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe('DatePipe', () => {
|
describe('DatePipe', () => {
|
||||||
var date: Date;
|
let date: Date;
|
||||||
var pipe: DatePipe;
|
let pipe: DatePipe;
|
||||||
|
|
||||||
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
|
// TODO: reactivate the disabled expectations once emulators are fixed in SauceLabs
|
||||||
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
|
// In some old versions of Chrome in Android emulators, time formatting returns dates in the
|
||||||
|
@ -34,7 +33,9 @@ export function main() {
|
||||||
|
|
||||||
describe('supports', () => {
|
describe('supports', () => {
|
||||||
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); });
|
||||||
|
|
||||||
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); });
|
||||||
|
|
||||||
it('should support numeric strings',
|
it('should support numeric strings',
|
||||||
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
() => { expect(() => pipe.transform('123456789')).not.toThrow(); });
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
export enum NumberFormatStyle {
|
export enum NumberFormatStyle {
|
||||||
Decimal,
|
Decimal,
|
||||||
Percent,
|
Percent,
|
||||||
Currency
|
Currency,
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NumberFormatter {
|
export class NumberFormatter {
|
||||||
|
@ -37,10 +37,13 @@ export class NumberFormatter {
|
||||||
return new Intl.NumberFormat(locale, options).format(num);
|
return new Intl.NumberFormat(locale, options).format(num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var DATE_FORMATS_SPLIT =
|
|
||||||
|
type DateFormatterFn = (date: Date, locale: string) => string;
|
||||||
|
|
||||||
|
const DATE_FORMATS_SPLIT =
|
||||||
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
|
/((?:[^yMLdHhmsazZEwGjJ']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|J+|j+|m+|s+|a|z|Z|G+|w+))(.*)/;
|
||||||
|
|
||||||
var PATTERN_ALIASES = {
|
const PATTERN_ALIASES: {[format: string]: DateFormatterFn} = {
|
||||||
yMMMdjms: datePartGetterFactory(combine([
|
yMMMdjms: datePartGetterFactory(combine([
|
||||||
digitCondition('year', 1),
|
digitCondition('year', 1),
|
||||||
nameCondition('month', 3),
|
nameCondition('month', 3),
|
||||||
|
@ -68,7 +71,7 @@ var PATTERN_ALIASES = {
|
||||||
jm: datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
|
jm: datePartGetterFactory(combine([digitCondition('hour', 1), digitCondition('minute', 1)]))
|
||||||
};
|
};
|
||||||
|
|
||||||
var DATE_FORMATS = {
|
const DATE_FORMATS: {[format: string]: DateFormatterFn} = {
|
||||||
yyyy: datePartGetterFactory(digitCondition('year', 4)),
|
yyyy: datePartGetterFactory(digitCondition('year', 4)),
|
||||||
yy: datePartGetterFactory(digitCondition('year', 2)),
|
yy: datePartGetterFactory(digitCondition('year', 2)),
|
||||||
y: datePartGetterFactory(digitCondition('year', 1)),
|
y: datePartGetterFactory(digitCondition('year', 1)),
|
||||||
|
@ -81,11 +84,11 @@ var DATE_FORMATS = {
|
||||||
dd: datePartGetterFactory(digitCondition('day', 2)),
|
dd: datePartGetterFactory(digitCondition('day', 2)),
|
||||||
d: datePartGetterFactory(digitCondition('day', 1)),
|
d: datePartGetterFactory(digitCondition('day', 1)),
|
||||||
HH: digitModifier(
|
HH: digitModifier(
|
||||||
hourExtracter(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
|
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), false)))),
|
||||||
H: hourExtracter(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
|
H: hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), false))),
|
||||||
hh: digitModifier(
|
hh: digitModifier(
|
||||||
hourExtracter(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
|
hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 2), true)))),
|
||||||
h: hourExtracter(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
h: hourExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||||
jj: datePartGetterFactory(digitCondition('hour', 2)),
|
jj: datePartGetterFactory(digitCondition('hour', 2)),
|
||||||
j: datePartGetterFactory(digitCondition('hour', 1)),
|
j: datePartGetterFactory(digitCondition('hour', 1)),
|
||||||
mm: digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
|
mm: digitModifier(datePartGetterFactory(digitCondition('minute', 2))),
|
||||||
|
@ -100,7 +103,7 @@ var DATE_FORMATS = {
|
||||||
EEE: datePartGetterFactory(nameCondition('weekday', 3)),
|
EEE: datePartGetterFactory(nameCondition('weekday', 3)),
|
||||||
EE: datePartGetterFactory(nameCondition('weekday', 2)),
|
EE: datePartGetterFactory(nameCondition('weekday', 2)),
|
||||||
E: datePartGetterFactory(nameCondition('weekday', 1)),
|
E: datePartGetterFactory(nameCondition('weekday', 1)),
|
||||||
a: hourClockExtracter(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
a: hourClockExtractor(datePartGetterFactory(hour12Modify(digitCondition('hour', 1), true))),
|
||||||
Z: timeZoneGetter('short'),
|
Z: timeZoneGetter('short'),
|
||||||
z: timeZoneGetter('long'),
|
z: timeZoneGetter('long'),
|
||||||
ww: datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
|
ww: datePartGetterFactory({}), // Week of year, padded (00-53). Week 01 is the week with the
|
||||||
|
@ -114,38 +117,26 @@ var DATE_FORMATS = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function digitModifier(inner: (date: Date, locale: string) => string): (
|
function digitModifier(inner: DateFormatterFn): DateFormatterFn {
|
||||||
date: Date, locale: string) => string {
|
|
||||||
return function(date: Date, locale: string): string {
|
return function(date: Date, locale: string): string {
|
||||||
var result = inner(date, locale);
|
const result = inner(date, locale);
|
||||||
|
|
||||||
return result.length == 1 ? '0' + result : result;
|
return result.length == 1 ? '0' + result : result;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function hourClockExtracter(inner: (date: Date, locale: string) => string): (
|
function hourClockExtractor(inner: DateFormatterFn): DateFormatterFn {
|
||||||
date: Date, locale: string) => string {
|
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[1]; };
|
||||||
return function(date: Date, locale: string): string {
|
|
||||||
var result = inner(date, locale);
|
|
||||||
|
|
||||||
return result.split(' ')[1];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hourExtracter(inner: (date: Date, locale: string) => string): (
|
function hourExtractor(inner: DateFormatterFn): DateFormatterFn {
|
||||||
date: Date, locale: string) => string {
|
return function(date: Date, locale: string): string { return inner(date, locale).split(' ')[0]; };
|
||||||
return function(date: Date, locale: string): string {
|
|
||||||
var result = inner(date, locale);
|
|
||||||
|
|
||||||
return result.split(' ')[0];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function intlDateFormat(date: Date, locale: string, options: Intl.DateTimeFormatOptions): string {
|
function intlDateFormat(date: Date, locale: string, options: Intl.DateTimeFormatOptions): string {
|
||||||
return new Intl.DateTimeFormat(locale, options).format(date).replace(/[\u200e\u200f]/g, '');
|
return new Intl.DateTimeFormat(locale, options).format(date).replace(/[\u200e\u200f]/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function timeZoneGetter(timezone: string): (date: Date, locale: string) => string {
|
function timeZoneGetter(timezone: string): DateFormatterFn {
|
||||||
// To workaround `Intl` API restriction for single timezone let format with 24 hours
|
// To workaround `Intl` API restriction for single timezone let format with 24 hours
|
||||||
const options = {hour: '2-digit', hour12: false, timeZoneName: timezone};
|
const options = {hour: '2-digit', hour12: false, timeZoneName: timezone};
|
||||||
return function(date: Date, locale: string): string {
|
return function(date: Date, locale: string): string {
|
||||||
|
@ -179,40 +170,31 @@ function nameCondition(prop: string, len: number): Intl.DateTimeFormatOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
function combine(options: Intl.DateTimeFormatOptions[]): Intl.DateTimeFormatOptions {
|
function combine(options: Intl.DateTimeFormatOptions[]): Intl.DateTimeFormatOptions {
|
||||||
var result = {};
|
return (<any>Object).assign({}, ...options);
|
||||||
|
|
||||||
options.forEach(option => { (<any>Object).assign(result, option); });
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function datePartGetterFactory(ret: Intl.DateTimeFormatOptions): (date: Date, locale: string) =>
|
function datePartGetterFactory(ret: Intl.DateTimeFormatOptions): DateFormatterFn {
|
||||||
string {
|
|
||||||
return (date: Date, locale: string): string => intlDateFormat(date, locale, ret);
|
return (date: Date, locale: string): string => intlDateFormat(date, locale, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DATE_FORMATTER_CACHE = new Map<string, string[]>();
|
||||||
var datePartsFormatterCache: Map<string, string[]> = new Map<string, string[]>();
|
|
||||||
|
|
||||||
function dateFormatter(format: string, date: Date, locale: string): string {
|
function dateFormatter(format: string, date: Date, locale: string): string {
|
||||||
var text = '';
|
let fn = PATTERN_ALIASES[format];
|
||||||
var match: any /** TODO #9100 */;
|
|
||||||
var fn: any /** TODO #9100 */;
|
|
||||||
var parts: string[] = [];
|
|
||||||
if ((PATTERN_ALIASES as any /** TODO #9100 */)[format]) {
|
|
||||||
return (PATTERN_ALIASES as any /** TODO #9100 */)[format](date, locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (fn) return fn(date, locale);
|
||||||
|
|
||||||
if (datePartsFormatterCache.has(format)) {
|
let parts = DATE_FORMATTER_CACHE.get(format);
|
||||||
parts = datePartsFormatterCache.get(format);
|
|
||||||
} else {
|
if (!parts) {
|
||||||
const matches = DATE_FORMATS_SPLIT.exec(format);
|
parts = [];
|
||||||
|
let match: RegExpExecArray;
|
||||||
|
DATE_FORMATS_SPLIT.exec(format);
|
||||||
|
|
||||||
while (format) {
|
while (format) {
|
||||||
match = DATE_FORMATS_SPLIT.exec(format);
|
match = DATE_FORMATS_SPLIT.exec(format);
|
||||||
if (match) {
|
if (match) {
|
||||||
parts = concat(parts, match, 1);
|
parts = parts.concat(match.slice(1));
|
||||||
format = parts.pop();
|
format = parts.pop();
|
||||||
} else {
|
} else {
|
||||||
parts.push(format);
|
parts.push(format);
|
||||||
|
@ -220,23 +202,17 @@ function dateFormatter(format: string, date: Date, locale: string): string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
datePartsFormatterCache.set(format, parts);
|
DATE_FORMATTER_CACHE.set(format, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.forEach(part => {
|
return parts.reduce((text, part) => {
|
||||||
fn = (DATE_FORMATS as any /** TODO #9100 */)[part];
|
let fn = DATE_FORMATS[part];
|
||||||
text += fn ? fn(date, locale) :
|
return text + (fn ? fn(date, locale) : partToTime(part));
|
||||||
part === '\'\'' ? '\'' : part.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
|
}, '');
|
||||||
});
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var slice = [].slice;
|
function partToTime(part: string): string {
|
||||||
function concat(
|
return part === '\'\'' ? '\'' : part.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
|
||||||
array1: any /** TODO #9100 */, array2: any /** TODO #9100 */,
|
|
||||||
index: any /** TODO #9100 */): string[] {
|
|
||||||
return array1.concat(slice.call(array2, index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DateFormatter {
|
export class DateFormatter {
|
||||||
|
|
Loading…
Reference in New Issue