@phensley/plurals
Advanced tools
Comparing version 0.22.3 to 0.23.0
import { Decimal } from '@phensley/decimal'; | ||
/** | ||
* Computes each number operands field as needed. | ||
* Operands for use in evaluating localized plural rules: | ||
* See: http://www.unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings | ||
* | ||
* symbol value | ||
* ---------------- | ||
* n absolute value of the source number (integer and decimals) | ||
* i integer digits of n | ||
* v number of visible fraction digits in n, with trailing zeros | ||
* w number of visible fraction digits in n, without trailing zeros | ||
* f visible fractional digits in n, with trailing zeros | ||
* t visible fractional digits in n, without trailing zeros | ||
* | ||
* @alpha | ||
*/ | ||
export declare class NumberOperands { | ||
private n; | ||
private _i?; | ||
private _v?; | ||
private _w?; | ||
private _f?; | ||
private _t?; | ||
private _nz?; | ||
n: number; | ||
i: number; | ||
v: number; | ||
w: number; | ||
f: number; | ||
t: number; | ||
constructor(d: Decimal); | ||
get i(): Decimal; | ||
get v(): Decimal; | ||
get w(): Decimal; | ||
get f(): Decimal; | ||
get t(): Decimal; | ||
toString(): string; | ||
protected get nz(): Decimal; | ||
} |
@@ -1,84 +0,158 @@ | ||
import { Decimal } from '@phensley/decimal'; | ||
var ZERO = new Decimal('0'); | ||
/** | ||
* Returns the number of digits in w, where w < RADIX. | ||
*/ | ||
var digitCount = function (w) { | ||
if (w < 10000 /* P4 */) { | ||
if (w < 100 /* P2 */) { | ||
return w < 10 /* P1 */ ? 1 : 2; | ||
} | ||
return w < 1000 /* P3 */ ? 3 : 4; | ||
} | ||
if (w < 1000000 /* P6 */) { | ||
return w < 100000 /* P5 */ ? 5 : 6; | ||
} | ||
return w < 10000000 /* P7 */ ? 7 : 8; | ||
}; | ||
var POWERS10 = [ | ||
1 /* P0 */, | ||
10 /* P1 */, | ||
100 /* P2 */, | ||
1000 /* P3 */, | ||
10000 /* P4 */, | ||
100000 /* P5 */, | ||
1000000 /* P6 */, | ||
10000000 /* P7 */, | ||
100000000 /* P8 */ | ||
]; | ||
// When a number crosses this limit we reduce it to avoid overflow. | ||
// This limit is chosen so that a number <= this limit multipled | ||
// by 10 will still be < MAX_SAFE_INTEGER. | ||
var LIMIT = 10000000000000; | ||
var FIELDS = ['n', 'i', 'v', 'w', 'f', 't']; | ||
var fracs = function (a, b) { | ||
var n = a.subtract(b); | ||
var s = n.scale(); | ||
return s > 0 ? n.movePoint(s) : n; | ||
}; | ||
var scale = function (n) { | ||
var s = n.scale(); | ||
return s > 0 ? new Decimal(s) : ZERO; | ||
}; | ||
/** | ||
* Computes each number operands field as needed. | ||
* Operands for use in evaluating localized plural rules: | ||
* See: http://www.unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings | ||
* | ||
* symbol value | ||
* ---------------- | ||
* n absolute value of the source number (integer and decimals) | ||
* i integer digits of n | ||
* v number of visible fraction digits in n, with trailing zeros | ||
* w number of visible fraction digits in n, without trailing zeros | ||
* f visible fractional digits in n, with trailing zeros | ||
* t visible fractional digits in n, without trailing zeros | ||
* | ||
* @alpha | ||
*/ | ||
var NumberOperands = /** @class */ (function () { | ||
function NumberOperands(d) { | ||
this.n = d.isFinite() ? d.abs() : ZERO; | ||
} | ||
Object.defineProperty(NumberOperands.prototype, "i", { | ||
get: function () { | ||
if (!this._i) { | ||
this._i = this.n.toInteger(); | ||
this.n = 0; | ||
this.i = 0; | ||
this.v = 0; | ||
this.w = 0; | ||
this.f = 0; | ||
this.t = 0; | ||
var props = d.properties(); | ||
var flag = props[3]; | ||
if (flag) { | ||
return; | ||
} | ||
var data = props[0]; | ||
var exp = props[2]; | ||
var len = data.length; | ||
var last = len - 1; | ||
// const neg = sign === -1; | ||
// const dec = exp < 0; | ||
var precision = (last * 7 /* RDIGITS */) + digitCount(data[last]); | ||
// Local operands | ||
var n = 0; | ||
var v = exp < 0 ? -exp : 0; | ||
var w = 0; | ||
var f = 0; | ||
var t = 0; | ||
// Count trailing zeros | ||
var trail = 0; | ||
// Index of radix digit | ||
var x = last; | ||
// Index of decimal digit in radix digit | ||
var y = 0; | ||
var intdigits = precision + exp; | ||
// Leading decimal zeros aren't part of the operands. | ||
if (intdigits < 0) { | ||
intdigits = 0; | ||
} | ||
outer: | ||
// Start at most-significant digit to least | ||
while (x >= 0) { | ||
var r = data[x]; | ||
var c = x !== last ? 7 /* RDIGITS */ : digitCount(r); | ||
y = c - 1; | ||
// Scan each decimal digit of the radix number from | ||
// most- to least- significant. | ||
while (y >= 0) { | ||
var p = POWERS10[y]; | ||
var q = (r / POWERS10[y]) | 0; | ||
if (intdigits > 0) { | ||
// Integer part | ||
n = (n * 10) + q; | ||
// If the integer digits exceed the limit we apply modulus. | ||
if (n > LIMIT) { | ||
// Stay below the limit but preserve (a) the magnitude and (b) as | ||
// many of the least-significant digits as possible | ||
n = (n % LIMIT) + LIMIT; | ||
} | ||
intdigits--; | ||
} | ||
else { | ||
// Decimal part | ||
if (q === 0) { | ||
trail++; | ||
} | ||
else { | ||
trail = 0; | ||
} | ||
f = (f * 10) + q; | ||
} | ||
// If the decimal digits exceed our limit we bail out early. | ||
if (f > LIMIT) { | ||
break outer; | ||
} | ||
r %= p; | ||
y--; | ||
} | ||
return this._i; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "v", { | ||
get: function () { | ||
if (!this._v) { | ||
this._v = scale(this.n); | ||
x--; | ||
} | ||
// Trailing integer zeros | ||
while (exp > 0) { | ||
n *= 10; | ||
if (n > LIMIT) { | ||
// Stay below the limit but preserve (a) the magnitude and (b) as | ||
// many of the least-significant digits as possible | ||
n = (n % LIMIT) + LIMIT; | ||
} | ||
return this._v; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "w", { | ||
get: function () { | ||
if (!this._w) { | ||
this._w = scale(this.nz); | ||
exp--; | ||
} | ||
// Special case for zero with exponent, e.g. '0.00'. | ||
if (len === 1 && data[0] === 0 && exp < 0) { | ||
w = 0; | ||
} | ||
else { | ||
w = v - trail; | ||
t = f; | ||
while (trail > 0) { | ||
t /= 10; | ||
trail--; | ||
} | ||
return this._w; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "f", { | ||
get: function () { | ||
if (!this._f) { | ||
this._f = fracs(this.n, this.i); | ||
} | ||
return this._f; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "t", { | ||
get: function () { | ||
if (!this._t) { | ||
this._t = fracs(this.nz, this.i); | ||
} | ||
return this._t; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
} | ||
this.n = n; | ||
this.i = n; | ||
this.v = v; | ||
this.w = w; | ||
this.f = f; | ||
this.t = t; | ||
} | ||
NumberOperands.prototype.toString = function () { | ||
var _this = this; | ||
return FIELDS.map(function (f) { return f + ": " + _this[f].toString(); }).join(', '); | ||
return FIELDS.map(function (f) { return f + ": " + _this[f]; }).join(', '); | ||
}; | ||
Object.defineProperty(NumberOperands.prototype, "nz", { | ||
get: function () { | ||
if (!this._nz) { | ||
this._nz = this.n.stripTrailingZeros(); | ||
} | ||
return this._nz; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
return NumberOperands; | ||
@@ -85,0 +159,0 @@ }()); |
@@ -63,6 +63,6 @@ import { Decimal, DecimalArg } from '@phensley/decimal'; | ||
readonly operator: string; | ||
readonly mod?: Decimal; | ||
readonly ranges: (Decimal | Decimal[])[]; | ||
readonly mod?: number; | ||
readonly ranges: (number | number[])[]; | ||
constructor(raw: string); | ||
} | ||
export declare const evaluateExpr: (operands: NumberOperands, expr: PluralExpr) => boolean; |
@@ -1,2 +0,2 @@ | ||
import { coerceDecimal, Decimal } from '@phensley/decimal'; | ||
import { coerceDecimal } from '@phensley/decimal'; | ||
import { NumberOperands } from './operands'; | ||
@@ -162,7 +162,7 @@ // Notation for categories in compact plural rules | ||
if (mod) { | ||
this.mod = new Decimal(mod); | ||
this.mod = mod; | ||
} | ||
raw = raw.substring(i); | ||
this.ranges = raw ? raw.split(',') | ||
.map(function (s) { return s.indexOf(':') === -1 ? new Decimal(s) : s.split(':').map(function (x) { return new Decimal(x); }); }) : []; | ||
.map(function (s) { return s.indexOf(':') === -1 ? Number(s) : s.split(':').map(function (x) { return Number(x); }); }) : []; | ||
} | ||
@@ -178,6 +178,9 @@ return PluralExpr; | ||
var n = operands[operand]; | ||
// The N = X..Y syntax means N matches an integer from X to Y inclusive | ||
// Operand 'n' must always be compared as an integer, so if it has any non-zero decimal | ||
// parts we must set integer = false. | ||
var integer = operand === 'n' ? operands.w === 0 : true; | ||
if (expr.mod) { | ||
n = n.divmod(expr.mod)[1]; | ||
n = n % expr.mod; | ||
} | ||
var integer = n.isInteger(); | ||
var equals = expr.operator !== '!'; | ||
@@ -188,7 +191,7 @@ var len = ranges.length; | ||
var elem = ranges[i]; | ||
if (elem instanceof Decimal) { | ||
res = res || n.compare(elem) === 0; | ||
if (typeof elem === 'number') { | ||
res = res || (integer && n === elem); | ||
} | ||
else { | ||
res = res || (integer && n.compare(elem[0]) >= 0 && n.compare(elem[1]) <= 0); | ||
res = res || (integer && elem[0] <= n && n <= elem[1]); | ||
} | ||
@@ -195,0 +198,0 @@ } |
import { Decimal } from '@phensley/decimal'; | ||
/** | ||
* Computes each number operands field as needed. | ||
* Operands for use in evaluating localized plural rules: | ||
* See: http://www.unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings | ||
* | ||
* symbol value | ||
* ---------------- | ||
* n absolute value of the source number (integer and decimals) | ||
* i integer digits of n | ||
* v number of visible fraction digits in n, with trailing zeros | ||
* w number of visible fraction digits in n, without trailing zeros | ||
* f visible fractional digits in n, with trailing zeros | ||
* t visible fractional digits in n, without trailing zeros | ||
* | ||
* @alpha | ||
*/ | ||
export declare class NumberOperands { | ||
private n; | ||
private _i?; | ||
private _v?; | ||
private _w?; | ||
private _f?; | ||
private _t?; | ||
private _nz?; | ||
n: number; | ||
i: number; | ||
v: number; | ||
w: number; | ||
f: number; | ||
t: number; | ||
constructor(d: Decimal); | ||
get i(): Decimal; | ||
get v(): Decimal; | ||
get w(): Decimal; | ||
get f(): Decimal; | ||
get t(): Decimal; | ||
toString(): string; | ||
protected get nz(): Decimal; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var decimal_1 = require("@phensley/decimal"); | ||
var ZERO = new decimal_1.Decimal('0'); | ||
/** | ||
* Returns the number of digits in w, where w < RADIX. | ||
*/ | ||
var digitCount = function (w) { | ||
if (w < 10000 /* P4 */) { | ||
if (w < 100 /* P2 */) { | ||
return w < 10 /* P1 */ ? 1 : 2; | ||
} | ||
return w < 1000 /* P3 */ ? 3 : 4; | ||
} | ||
if (w < 1000000 /* P6 */) { | ||
return w < 100000 /* P5 */ ? 5 : 6; | ||
} | ||
return w < 10000000 /* P7 */ ? 7 : 8; | ||
}; | ||
var POWERS10 = [ | ||
1 /* P0 */, | ||
10 /* P1 */, | ||
100 /* P2 */, | ||
1000 /* P3 */, | ||
10000 /* P4 */, | ||
100000 /* P5 */, | ||
1000000 /* P6 */, | ||
10000000 /* P7 */, | ||
100000000 /* P8 */ | ||
]; | ||
// When a number crosses this limit we reduce it to avoid overflow. | ||
// This limit is chosen so that a number <= this limit multipled | ||
// by 10 will still be < MAX_SAFE_INTEGER. | ||
var LIMIT = 10000000000000; | ||
var FIELDS = ['n', 'i', 'v', 'w', 'f', 't']; | ||
var fracs = function (a, b) { | ||
var n = a.subtract(b); | ||
var s = n.scale(); | ||
return s > 0 ? n.movePoint(s) : n; | ||
}; | ||
var scale = function (n) { | ||
var s = n.scale(); | ||
return s > 0 ? new decimal_1.Decimal(s) : ZERO; | ||
}; | ||
/** | ||
* Computes each number operands field as needed. | ||
* Operands for use in evaluating localized plural rules: | ||
* See: http://www.unicode.org/reports/tr35/tr35-numbers.html#Plural_Operand_Meanings | ||
* | ||
* symbol value | ||
* ---------------- | ||
* n absolute value of the source number (integer and decimals) | ||
* i integer digits of n | ||
* v number of visible fraction digits in n, with trailing zeros | ||
* w number of visible fraction digits in n, without trailing zeros | ||
* f visible fractional digits in n, with trailing zeros | ||
* t visible fractional digits in n, without trailing zeros | ||
* | ||
* @alpha | ||
*/ | ||
var NumberOperands = /** @class */ (function () { | ||
function NumberOperands(d) { | ||
this.n = d.isFinite() ? d.abs() : ZERO; | ||
} | ||
Object.defineProperty(NumberOperands.prototype, "i", { | ||
get: function () { | ||
if (!this._i) { | ||
this._i = this.n.toInteger(); | ||
this.n = 0; | ||
this.i = 0; | ||
this.v = 0; | ||
this.w = 0; | ||
this.f = 0; | ||
this.t = 0; | ||
var props = d.properties(); | ||
var flag = props[3]; | ||
if (flag) { | ||
return; | ||
} | ||
var data = props[0]; | ||
var exp = props[2]; | ||
var len = data.length; | ||
var last = len - 1; | ||
// const neg = sign === -1; | ||
// const dec = exp < 0; | ||
var precision = (last * 7 /* RDIGITS */) + digitCount(data[last]); | ||
// Local operands | ||
var n = 0; | ||
var v = exp < 0 ? -exp : 0; | ||
var w = 0; | ||
var f = 0; | ||
var t = 0; | ||
// Count trailing zeros | ||
var trail = 0; | ||
// Index of radix digit | ||
var x = last; | ||
// Index of decimal digit in radix digit | ||
var y = 0; | ||
var intdigits = precision + exp; | ||
// Leading decimal zeros aren't part of the operands. | ||
if (intdigits < 0) { | ||
intdigits = 0; | ||
} | ||
outer: | ||
// Start at most-significant digit to least | ||
while (x >= 0) { | ||
var r = data[x]; | ||
var c = x !== last ? 7 /* RDIGITS */ : digitCount(r); | ||
y = c - 1; | ||
// Scan each decimal digit of the radix number from | ||
// most- to least- significant. | ||
while (y >= 0) { | ||
var p = POWERS10[y]; | ||
var q = (r / POWERS10[y]) | 0; | ||
if (intdigits > 0) { | ||
// Integer part | ||
n = (n * 10) + q; | ||
// If the integer digits exceed the limit we apply modulus. | ||
if (n > LIMIT) { | ||
// Stay below the limit but preserve (a) the magnitude and (b) as | ||
// many of the least-significant digits as possible | ||
n = (n % LIMIT) + LIMIT; | ||
} | ||
intdigits--; | ||
} | ||
else { | ||
// Decimal part | ||
if (q === 0) { | ||
trail++; | ||
} | ||
else { | ||
trail = 0; | ||
} | ||
f = (f * 10) + q; | ||
} | ||
// If the decimal digits exceed our limit we bail out early. | ||
if (f > LIMIT) { | ||
break outer; | ||
} | ||
r %= p; | ||
y--; | ||
} | ||
return this._i; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "v", { | ||
get: function () { | ||
if (!this._v) { | ||
this._v = scale(this.n); | ||
x--; | ||
} | ||
// Trailing integer zeros | ||
while (exp > 0) { | ||
n *= 10; | ||
if (n > LIMIT) { | ||
// Stay below the limit but preserve (a) the magnitude and (b) as | ||
// many of the least-significant digits as possible | ||
n = (n % LIMIT) + LIMIT; | ||
} | ||
return this._v; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "w", { | ||
get: function () { | ||
if (!this._w) { | ||
this._w = scale(this.nz); | ||
exp--; | ||
} | ||
// Special case for zero with exponent, e.g. '0.00'. | ||
if (len === 1 && data[0] === 0 && exp < 0) { | ||
w = 0; | ||
} | ||
else { | ||
w = v - trail; | ||
t = f; | ||
while (trail > 0) { | ||
t /= 10; | ||
trail--; | ||
} | ||
return this._w; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "f", { | ||
get: function () { | ||
if (!this._f) { | ||
this._f = fracs(this.n, this.i); | ||
} | ||
return this._f; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NumberOperands.prototype, "t", { | ||
get: function () { | ||
if (!this._t) { | ||
this._t = fracs(this.nz, this.i); | ||
} | ||
return this._t; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
} | ||
this.n = n; | ||
this.i = n; | ||
this.v = v; | ||
this.w = w; | ||
this.f = f; | ||
this.t = t; | ||
} | ||
NumberOperands.prototype.toString = function () { | ||
var _this = this; | ||
return FIELDS.map(function (f) { return f + ": " + _this[f].toString(); }).join(', '); | ||
return FIELDS.map(function (f) { return f + ": " + _this[f]; }).join(', '); | ||
}; | ||
Object.defineProperty(NumberOperands.prototype, "nz", { | ||
get: function () { | ||
if (!this._nz) { | ||
this._nz = this.n.stripTrailingZeros(); | ||
} | ||
return this._nz; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
return NumberOperands; | ||
@@ -87,0 +161,0 @@ }()); |
@@ -63,6 +63,6 @@ import { Decimal, DecimalArg } from '@phensley/decimal'; | ||
readonly operator: string; | ||
readonly mod?: Decimal; | ||
readonly ranges: (Decimal | Decimal[])[]; | ||
readonly mod?: number; | ||
readonly ranges: (number | number[])[]; | ||
constructor(raw: string); | ||
} | ||
export declare const evaluateExpr: (operands: NumberOperands, expr: PluralExpr) => boolean; |
@@ -164,7 +164,7 @@ "use strict"; | ||
if (mod) { | ||
this.mod = new decimal_1.Decimal(mod); | ||
this.mod = mod; | ||
} | ||
raw = raw.substring(i); | ||
this.ranges = raw ? raw.split(',') | ||
.map(function (s) { return s.indexOf(':') === -1 ? new decimal_1.Decimal(s) : s.split(':').map(function (x) { return new decimal_1.Decimal(x); }); }) : []; | ||
.map(function (s) { return s.indexOf(':') === -1 ? Number(s) : s.split(':').map(function (x) { return Number(x); }); }) : []; | ||
} | ||
@@ -180,6 +180,9 @@ return PluralExpr; | ||
var n = operands[operand]; | ||
// The N = X..Y syntax means N matches an integer from X to Y inclusive | ||
// Operand 'n' must always be compared as an integer, so if it has any non-zero decimal | ||
// parts we must set integer = false. | ||
var integer = operand === 'n' ? operands.w === 0 : true; | ||
if (expr.mod) { | ||
n = n.divmod(expr.mod)[1]; | ||
n = n % expr.mod; | ||
} | ||
var integer = n.isInteger(); | ||
var equals = expr.operator !== '!'; | ||
@@ -190,7 +193,7 @@ var len = ranges.length; | ||
var elem = ranges[i]; | ||
if (elem instanceof decimal_1.Decimal) { | ||
res = res || n.compare(elem) === 0; | ||
if (typeof elem === 'number') { | ||
res = res || (integer && n === elem); | ||
} | ||
else { | ||
res = res || (integer && n.compare(elem[0]) >= 0 && n.compare(elem[1]) <= 0); | ||
res = res || (integer && elem[0] <= n && n <= elem[1]); | ||
} | ||
@@ -197,0 +200,0 @@ } |
{ | ||
"name": "@phensley/plurals", | ||
"version": "0.22.3", | ||
"version": "0.23.0", | ||
"description": "Plural rules engine", | ||
@@ -37,3 +37,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@phensley/decimal": "0.22.3", | ||
"@phensley/decimal": "0.23.0", | ||
"tslib": "1.10.x" | ||
@@ -67,3 +67,3 @@ }, | ||
}, | ||
"gitHead": "1ab9845b2f07e1bfc1f6ed8716a55eaaca4eecb9" | ||
"gitHead": "8aa8004dbd6ea152a729226d3a1852de3fca2aea" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
98793
1817
+ Added@phensley/decimal@0.23.0(transitive)
- Removed@phensley/decimal@0.22.3(transitive)
Updated@phensley/decimal@0.23.0