-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add "number-format" expression for string representation of numbers..
- Loading branch information
Showing
7 changed files
with
245 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// @flow | ||
|
||
import { StringType, NumberType } from '../types'; | ||
|
||
import type { Expression } from '../expression'; | ||
import type EvaluationContext from '../evaluation_context'; | ||
import type ParsingContext from '../parsing_context'; | ||
import type { Type } from '../types'; | ||
|
||
declare var Intl: { | ||
NumberFormat: Class<Intl$NumberFormat> | ||
}; | ||
|
||
declare class Intl$NumberFormat { | ||
constructor ( | ||
locales?: string | string[], | ||
options?: NumberFormatOptions | ||
): Intl$NumberFormat; | ||
|
||
static ( | ||
locales?: string | string[], | ||
options?: NumberFormatOptions | ||
): Intl$NumberFormat; | ||
|
||
format(a: number): string; | ||
|
||
resolvedOptions(): any; | ||
} | ||
|
||
type NumberFormatOptions = { | ||
style?: 'decimal' | 'currency' | 'percent'; | ||
currency?: null | string; | ||
minimumFractionDigits?: null | string; | ||
maximumFractionDigits?: null | string; | ||
}; | ||
|
||
export default class NumberFormat implements Expression { | ||
type: Type; | ||
number: Expression; | ||
locale: Expression | null; // BCP 47 language tag | ||
currency: Expression | null; // ISO 4217 currency code, required if style=currency | ||
minFractionDigits: Expression | null; // Default 0 | ||
maxFractionDigits: Expression | null; // Default 3 | ||
|
||
constructor(number: Expression, | ||
locale: Expression | null, | ||
currency: Expression | null, | ||
minFractionDigits: Expression | null, | ||
maxFractionDigits: Expression | null) { | ||
this.type = StringType; | ||
this.number = number; | ||
this.locale = locale; | ||
this.currency = currency; | ||
this.minFractionDigits = minFractionDigits; | ||
this.maxFractionDigits = maxFractionDigits; | ||
} | ||
|
||
static parse(args: Array<mixed>, context: ParsingContext): ?Expression { | ||
if (args.length !== 3) | ||
return context.error(`Expected two arguments.`); | ||
|
||
const number = context.parse(args[1], 1, NumberType); | ||
if (!number) return null; | ||
|
||
const options = (args[2]: any); | ||
if (typeof options !== "object" || Array.isArray(options)) | ||
return context.error(`NumberFormat options argument must be an object.`); | ||
|
||
let locale = null; | ||
if (options['locale']) { | ||
locale = context.parse(options['locale'], 1, StringType); | ||
if (!locale) return null; | ||
} | ||
|
||
let currency = null; | ||
if (options['currency']) { | ||
currency = context.parse(options['currency'], 1, StringType); | ||
if (!currency) return null; | ||
} | ||
|
||
let minFractionDigits = null; | ||
if (options['min-fraction-digits']) { | ||
minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType); | ||
if (!minFractionDigits) return null; | ||
} | ||
|
||
let maxFractionDigits = null; | ||
if (options['max-fraction-digits']) { | ||
maxFractionDigits = context.parse(options['max-fraction-digits'], 1, NumberType); | ||
if (!maxFractionDigits) return null; | ||
} | ||
|
||
return new NumberFormat(number, locale, currency, minFractionDigits, maxFractionDigits); | ||
} | ||
|
||
evaluate(ctx: EvaluationContext) { | ||
return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [], | ||
{ | ||
style: this.currency ? "currency" : "decimal", | ||
currency: this.currency ? this.currency.evaluate(ctx) : undefined, | ||
minimumFractionDigits: this.minFractionDigits ? this.minFractionDigits.evaluate(ctx) : undefined, | ||
maximumFractionDigits: this.maxFractionDigits ? this.maxFractionDigits.evaluate(ctx) : undefined, | ||
}).format(this.number.evaluate(ctx)); | ||
} | ||
|
||
eachChild(fn: (Expression) => void) { | ||
fn(this.number); | ||
if (this.locale) { | ||
fn(this.locale); | ||
} | ||
if (this.currency) { | ||
fn(this.currency); | ||
} | ||
if (this.minFractionDigits) { | ||
fn(this.minFractionDigits); | ||
} | ||
if (this.maxFractionDigits) { | ||
fn(this.maxFractionDigits); | ||
} | ||
} | ||
|
||
possibleOutputs() { | ||
return [undefined]; | ||
} | ||
|
||
serialize() { | ||
const options = {}; | ||
if (this.locale) { | ||
options['locale'] = this.locale.serialize(); | ||
} | ||
if (this.currency) { | ||
options['currency'] = this.currency.serialize(); | ||
} | ||
if (this.minFractionDigits) { | ||
options['min-fraction-digits'] = this.minFractionDigits.serialize(); | ||
} | ||
if (this.maxFractionDigits) { | ||
options['max-fraction-digits'] = this.maxFractionDigits.serialize(); | ||
} | ||
return ["number-format", this.number.serialize(), options]; | ||
} | ||
} |
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
31 changes: 31 additions & 0 deletions
31
test/integration/expression-tests/number-format/currency/test.json
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,31 @@ | ||
{ | ||
"expression": [ | ||
"number-format", | ||
123456.789, | ||
{ | ||
"locale": ["get", "locale"], | ||
"currency": ["get", "currency"] | ||
} | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"locale": "ja-JP", "currency": "JPY"}}], | ||
[{}, {"properties": {"locale": "de-DE", "currency": "EUR"}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "string" | ||
}, | ||
"outputs": ["JP¥ 123,457", "€ 123,456.79"], | ||
"serialized": [ | ||
"number-format", | ||
123456.789, | ||
{ | ||
"locale": ["string", ["get", "locale"]], | ||
"currency": ["string", ["get", "currency"]] | ||
} | ||
] | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
test/integration/expression-tests/number-format/default/test.json
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,21 @@ | ||
|
||
{ | ||
"expression": [ | ||
"number-format", | ||
123456.789, | ||
{} | ||
], | ||
"inputs": [ | ||
[{}, {}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": true, | ||
"isZoomConstant": true, | ||
"type": "string" | ||
}, | ||
"outputs": ["123,456.789"], | ||
"serialized": "123,456.789" | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
test/integration/expression-tests/number-format/precision/test.json
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,33 @@ | ||
{ | ||
"expression": [ | ||
"number-format", | ||
987654321.23456789, | ||
{ | ||
"locale": ["get", "locale"], | ||
"min-fraction-digits": ["get", "min"], | ||
"max-fraction-digits": ["get", "max"] | ||
} | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"locale": "en-US", "min": 15, "max": 20}}], | ||
[{}, {"properties": {"locale": "en-US", "min": 2, "max": 4}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "string" | ||
}, | ||
"outputs": ["987,654,321.234568000000000", "987,654,321.2346"], | ||
"serialized": [ | ||
"number-format", | ||
987654321.2345679, | ||
{ | ||
"locale": ["string", ["get", "locale"]], | ||
"min-fraction-digits": ["number", ["get", "min"]], | ||
"max-fraction-digits": ["number", ["get", "max"]] | ||
} | ||
] | ||
} | ||
} |