mirror of
https://github.com/tenrok/numeralize-ru.git
synced 2026-05-15 11:59:43 +03:00
Rewritten to Typescript, added support for different module systems
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[package.json]
|
||||
indent_size = 2
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
]
|
||||
}
|
||||
@@ -101,3 +101,4 @@ Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
lib
|
||||
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
### Node template
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
|
||||
node_modules
|
||||
### OSX template
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
test
|
||||
@@ -16,53 +16,53 @@ npm install --save numeralize-ru
|
||||
|
||||
+ `number` — число, для которого надо записать числительное;
|
||||
+ `gender` — пол:
|
||||
+ `numeralize.GENDER_MASCULINE` — мужской (по умолчанию);
|
||||
+ `numeralize.GENDER_FEMININE` — женский;
|
||||
+ `numeralize.GENDER_NEUTER` — средний;
|
||||
+ `Gender.Masculine` — мужской (по умолчанию);
|
||||
+ `Gender.Feminine` — женский;
|
||||
+ `Gender.Neuter` — средний;
|
||||
+ `kase` — падеж (`case` является ключевым словом, поэтому не может быть использован в качестве имени переменной):
|
||||
+ `numeralize.CASE_NOMINATIVE` — именительный (по умолчанию);
|
||||
+ `numeralize.CASE_GENITIVE` — родительный;
|
||||
+ `numeralize.CASE_DATIVE` — дательный;
|
||||
+ `numeralize.CASE_ACCUSATIVE` — винительный;
|
||||
+ `numeralize.CASE_INSTRUMENTAL` — творительный;
|
||||
+ `numeralize.CASE_PREPOSITIONAL` — предложный;
|
||||
+ `Case.Nominative` — именительный (по умолчанию);
|
||||
+ `Case.Genitive` — родительный;
|
||||
+ `Case.Dative` — дательный;
|
||||
+ `Case.Accusative` — винительный;
|
||||
+ `Case.Instrumental` — творительный;
|
||||
+ `Case.Prepositional` — предложный;
|
||||
+ `animate` — являются ли перечисляемые предметы одушевлёнными (влияет на форму винительного падежа некоторых числительных)
|
||||
|
||||
```javascript
|
||||
const numeralize = require('numeralize-ru');
|
||||
```typescript
|
||||
import {Case, Gender, numeralize, pluralize} from 'numeralize-ru';
|
||||
|
||||
numeralize(5122981121);
|
||||
// мужской род, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одна тысяча сто двадцать один'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_FEMININE);
|
||||
numeralize(5122981121, Gender.Feminine);
|
||||
// женский род, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одна тысяча сто двадцать одна'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_NEUTER);
|
||||
numeralize(5122981121, Gender.Neuter);
|
||||
// средний род, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одна тысяча сто двадцать одно'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_NOMINATIVE);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Nominative);
|
||||
// мужской род, именительный падеж, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одна тысяча сто двадцать один'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_GENITIVE);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Genitive);
|
||||
// мужской род, родительный падеж, 'пяти миллиардов ста двадцати двух миллионов девятисот восьмидесяти одной тысячи ста двадцати одного'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_DATIVE);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Dative);
|
||||
// мужской род, дательный падеж, 'пяти миллиардам ста двадцати двум миллионам девятистам восьмидесяти одной тысяче ста двадцати одному'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_ACCUSATIVE);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Accusative);
|
||||
// мужской род, винительный падеж, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одну тысячу сто двадцать один'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_ACCUSATIVE, true);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Accusative, true);
|
||||
// мужской род, винительный падеж, одушевлённые предметы, 'пять миллиардов сто двадцать два миллиона девятьсот восемьдесят одну тысячу сто двадцать одного'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_INSTRUMENTAL);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Instrumental);
|
||||
// мужской род, творительный падеж, 'пятью миллиардами ста двадцатью двумя миллионами девятьюстами восемьюдесятью одной тысячей ста двадцатью одним'
|
||||
|
||||
numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_PREPOSITIONAL);
|
||||
numeralize(5122981121, Gender.Masculine, Case.Prepositional);
|
||||
// мужской род, творительный падеж, 'пяти миллиардах ста двадцати двух миллионах девятистах восьмидесяти одной тысяче ста двадцати одном'
|
||||
```
|
||||
|
||||
### `numeralize.pluralize(count, one, two, five)`
|
||||
### `pluralize(count, one, two, five)`
|
||||
|
||||
Выбирает нужную форму существительного в зависимости от количества.
|
||||
|
||||
@@ -71,8 +71,8 @@ numeralize(5122981121, numeralize.GENDER_MASCULINE, numeralize.CASE_PREPOSITIONA
|
||||
+ `two` — форма существительного для двух предметов, например, _рубля_;
|
||||
+ `five` — форма существительного для пяти предметов, например, _рублей_;
|
||||
|
||||
```javascript
|
||||
const pluralize = require('numeralize-ru').pluralize;
|
||||
```typescript
|
||||
import {pluralize} from 'numeralize-ru';
|
||||
|
||||
pluralize(0, 'рубль', 'рубля', 'рублей');
|
||||
// 'рублей'
|
||||
@@ -96,7 +96,6 @@ pluralize(22, 'рубль', 'рубля', 'рублей');
|
||||
// 'рубля'
|
||||
```
|
||||
|
||||
|
||||
# Roadmap
|
||||
|
||||
+ Порядковые числительные (ordinal numerals): _первый_, _вторым_, _третьими_ и т.д.
|
||||
|
||||
Vendored
-20
@@ -1,20 +0,0 @@
|
||||
export = numeralize;
|
||||
|
||||
declare function numeralize(number: number, gender?: numeralize.Gender, kase?: numeralize.Case, animate?: boolean): string;
|
||||
|
||||
declare namespace numeralize {
|
||||
export type Gender = number;
|
||||
export const GENDER_MASCULINE: Gender;
|
||||
export const GENDER_FEMININE: Gender;
|
||||
export const GENDER_NEUTER: Gender;
|
||||
|
||||
export type Case = number;
|
||||
export const CASE_NOMINATIVE: Case;
|
||||
export const CASE_GENITIVE: Case;
|
||||
export const CASE_DATIVE: Case;
|
||||
export const CASE_ACCUSATIVE: Case;
|
||||
export const CASE_INSTRUMENTAL: Case;
|
||||
export const CASE_PREPOSITIONAL: Case;
|
||||
|
||||
export function pluralize(count: number, one: string, two: string, five: string): string;
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
;(function(root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
root.numeralize = factory();
|
||||
}
|
||||
}(this, function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Numeralize number
|
||||
* @param {number} number Integer
|
||||
* @param {number} [gender=numeralize.GENDER_MASCULINE]
|
||||
* @param {number} [kase=numeralize.CASE_NOMINATIVE]
|
||||
* @param {boolean} [animate=false]
|
||||
* @returns {string}
|
||||
*/
|
||||
function numeralize(number, gender, kase, animate) {
|
||||
// Normalize params
|
||||
number = Math.abs(parseInt(number, 10));
|
||||
gender = gender || numeralize.GENDER_MASCULINE;
|
||||
kase = kase || numeralize.CASE_NOMINATIVE;
|
||||
animate = !!animate;
|
||||
|
||||
// Collect chunks
|
||||
var result = [];
|
||||
|
||||
// Descend known powers of thousand
|
||||
for (var l = LARGES.length, i = l; i >= 0; i--) {
|
||||
var base = Math.pow(10, i * 3);
|
||||
var current = Math.floor(number / base);
|
||||
number = number % base;
|
||||
|
||||
if (current) {
|
||||
var words = i ? LARGES[i] : null;
|
||||
var numeral = small(current, words ? words[0] : gender, kase, words ? false : animate);
|
||||
if (numeral) {
|
||||
result.push(numeral);
|
||||
if (words) {
|
||||
var plural = pluralize.apply(null, [current].concat(words[kase + 1]));
|
||||
result.push(plural);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zero
|
||||
if (!result.length) {
|
||||
return MINORS[0][kase];
|
||||
}
|
||||
|
||||
// Return
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeralize small number (< 1000)
|
||||
* @private
|
||||
* @param {number} number Non-negative integer < 1000
|
||||
* @param {number} gender
|
||||
* @param {number} kase
|
||||
* @param {boolean} animate
|
||||
* @returns {string}
|
||||
*/
|
||||
function small(number, gender, kase, animate) {
|
||||
// Zero
|
||||
if (0 === number) { return ""; }
|
||||
|
||||
// Collect chunks
|
||||
var result = [];
|
||||
|
||||
// Hundreds
|
||||
var hundreds = Math.floor(number / 100);
|
||||
if (HUNDREDS[hundreds]) {
|
||||
result.push(HUNDREDS[hundreds][kase]);
|
||||
}
|
||||
|
||||
// Tens
|
||||
var tens = Math.floor(number % 100 / 10);
|
||||
if (TENS[tens]) {
|
||||
result.push(TENS[tens][kase]);
|
||||
}
|
||||
|
||||
// Minors
|
||||
var minors = number % 100;
|
||||
if (minors >= MINORS.length) {
|
||||
minors = number % 10;
|
||||
}
|
||||
if (minors) {
|
||||
minors = MINORS[minors][kase];
|
||||
if ("string" !== typeof minors) {
|
||||
minors = minors[gender];
|
||||
if ("string" !== typeof minors) {
|
||||
minors = minors[animate ? 0 : 1];
|
||||
}
|
||||
}
|
||||
result.push(minors);
|
||||
}
|
||||
|
||||
// Return
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Pluralize noun according to count
|
||||
* @param {number} count Number of items
|
||||
* @param {string} one E.g. «рубль»
|
||||
* @param {string} two E.g. «рубля»
|
||||
* @param {string} five E.g. «рублей»
|
||||
* @returns {string}
|
||||
*/
|
||||
function pluralize(count, one, two, five) {
|
||||
count = Math.floor(Math.abs(count)) % 100;
|
||||
if (count > 10 && count < 20) {
|
||||
return five;
|
||||
}
|
||||
count = count % 10;
|
||||
if (1 === count) { return one; }
|
||||
if (count >= 2 && count <= 4) { return two; }
|
||||
return five;
|
||||
}
|
||||
|
||||
numeralize.GENDER_MASCULINE = 0;
|
||||
numeralize.GENDER_FEMININE = 1;
|
||||
numeralize.GENDER_NEUTER = 2;
|
||||
|
||||
numeralize.CASE_NOMINATIVE = 0;
|
||||
numeralize.CASE_GENITIVE = 1;
|
||||
numeralize.CASE_DATIVE = 2;
|
||||
numeralize.CASE_ACCUSATIVE = 3;
|
||||
numeralize.CASE_INSTRUMENTAL = 4;
|
||||
numeralize.CASE_PREPOSITIONAL = 5;
|
||||
|
||||
numeralize.pluralize = pluralize;
|
||||
|
||||
var MINORS = [
|
||||
['ноль', 'нуля', 'нулю', 'ноль', 'нулём', 'нуле'],
|
||||
[
|
||||
['один', 'одна', 'одно'],
|
||||
['одного', 'одной', 'одного'],
|
||||
['одному', 'одной', 'одному'],
|
||||
[['одного', 'один'], 'одну', 'одно'],
|
||||
['одним', 'одной', 'одним'],
|
||||
['одном', 'одной', 'одном']
|
||||
],
|
||||
[
|
||||
['два', 'две', 'два'],
|
||||
'двух',
|
||||
'двум',
|
||||
[['двух', 'два'], ['двух', 'две'], 'два'],
|
||||
'двумя',
|
||||
'двух'
|
||||
],
|
||||
[
|
||||
'три',
|
||||
'трёх',
|
||||
'трём',
|
||||
[['трёх', 'три'], ['трёх', 'три'], 'три'],
|
||||
'тремя',
|
||||
'трёх'
|
||||
],
|
||||
[
|
||||
'четыре',
|
||||
'четырёх',
|
||||
'четырём',
|
||||
[['четырёх', 'четыре'], ['четырёх', 'четыре'], 'четыре'],
|
||||
'четырьмя',
|
||||
'четырёх'
|
||||
],
|
||||
['пять', 'пяти', 'пяти', 'пять', 'пятью', 'пяти'],
|
||||
['шесть', 'шести', 'шести', 'шесть', 'шестью', 'шести'],
|
||||
['семь', 'семи', 'семи', 'семь', 'семью', 'семи'],
|
||||
['восемь', 'восьми', 'восьми', 'восемь', 'восемью', 'восьми'],
|
||||
['девять', 'девяти', 'девяти', 'девять', 'девятью', 'девяти'],
|
||||
['десять', 'десяти', 'десяти', 'десять', 'десятью', 'десяти']
|
||||
].concat(
|
||||
['один', 'две', 'три', 'четыр', 'пят', 'шест', 'сем', 'восем', 'девят'].map(function(prefix) {
|
||||
return ['надцать', 'надцати', 'надцати', 'надцать', 'надцатью', 'надцати'].map(function(suffix) {
|
||||
return prefix + suffix;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
var TENS = [
|
||||
false,
|
||||
false,
|
||||
['двадцать', 'двадцати', 'двадцати', 'двадцать', 'двадцатью', 'двадцати'],
|
||||
['тридцать', 'тридцати', 'тридцати', 'тридцать', 'тридцатью', 'тридцати'],
|
||||
['сорок', 'сорока', 'сорока', 'сорок', 'сорока', 'сорока'],
|
||||
['пятьдесят', 'пятидесяти', 'пятидесяти', 'пятьдесят', 'пятьюдесятью', 'пятидесяти'],
|
||||
['шестьдесят', 'шестидесяти', 'шестидесяти', 'шестьдесят', 'шестьюдесятью', 'шестидесяти'],
|
||||
['семьдесят', 'семидесяти', 'семидесяти', 'семьдесят', 'семьюдесятью', 'семидесяти'],
|
||||
['восемьдесят', 'восьмидесяти', 'восьмидесяти', 'восемьдесят', 'восемьюдесятью', 'восьмидесяти'],
|
||||
['девяносто', 'девяноста', 'девяноста', 'девяносто', 'девяноста', 'девяноста']
|
||||
];
|
||||
|
||||
var HUNDREDS = [
|
||||
false,
|
||||
['сто', 'ста', 'ста', 'сто', 'ста', 'ста'],
|
||||
['двести', 'двухсот', 'двумстам', 'двести', 'двумястами', 'двухстах'],
|
||||
['триста', 'трёхсот', 'трёмстам', 'триста', 'тремястами', 'трёхстах'],
|
||||
['четыреста', 'четырёхсот', 'четырёмстам', 'четыреста', 'четырьмястами', 'четырёхстах'],
|
||||
['пятьсот', 'пятисот', 'пятистам', 'пятьсот', 'пятьюстами', 'пятистах'],
|
||||
['шестьсот', 'шестисот', 'шестистам', 'шестьсот', 'шестьюстами', 'шестистах'],
|
||||
['семьсот', 'семисот', 'семистам', 'семьсот', 'семьюстами', 'семистах'],
|
||||
['восемьсот', 'восьмисот', 'восьмистам', 'восемьсот', 'восемьюстами', 'восьмистах'],
|
||||
['девятьсот', 'девятисот', 'девятистам', 'девятьсот', 'девятьюстами', 'девятистах']
|
||||
];
|
||||
|
||||
var LARGES = [
|
||||
false,
|
||||
[
|
||||
numeralize.GENDER_FEMININE,
|
||||
['тысяча', 'тысячи', 'тысяч'],
|
||||
['тысячи', 'тысяч', 'тысяч'],
|
||||
['тысяче', 'тысячам', 'тысячам'],
|
||||
['тысячу', 'тысячи', 'тысяч'],
|
||||
['тысячей', 'тысячами', 'тысячами'],
|
||||
['тысяче', 'тысячах', 'тысячах']
|
||||
]
|
||||
].concat(['миллион', 'миллиард', 'триллион'].map(function(base) {
|
||||
return [numeralize.GENDER_MASCULINE]
|
||||
.concat([
|
||||
['', 'а', 'ов'],
|
||||
['а', 'ов', 'ов'],
|
||||
['у', 'ам', 'ам'],
|
||||
['', 'а', 'ов'],
|
||||
['ом', 'ами', 'ами'],
|
||||
['е', 'ах', 'ах']
|
||||
].map(function(kase) {
|
||||
return kase.map(function(suffix) {
|
||||
return base + suffix;
|
||||
});
|
||||
}));
|
||||
}));
|
||||
|
||||
return numeralize;
|
||||
}));
|
||||
Generated
+2449
File diff suppressed because it is too large
Load Diff
+31
-9
@@ -1,13 +1,29 @@
|
||||
{
|
||||
"name": "numeralize-ru",
|
||||
"version": "1.0.1",
|
||||
"version": "2.0.0-alpha.1",
|
||||
"description": "Russian numerals",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"require": "./lib/cjs/index.js",
|
||||
"import": "./lib/esm/index.js",
|
||||
"default": "./lib/esm/index.js"
|
||||
}
|
||||
},
|
||||
"main": "lib/cjs/index.js",
|
||||
"files": [
|
||||
"lib/",
|
||||
"LICENSE.md",
|
||||
"README.md",
|
||||
"package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "npm run test:js; npm run test:ts",
|
||||
"test:js": "./node_modules/.bin/mocha",
|
||||
"test:ts": "./node_modules/.bin/tsc ./test/*.d.spec.ts --noEmit --noImplicitAny --strictNullChecks --target ES6",
|
||||
"dev": "./node_modules/.bin/mocha --watch"
|
||||
"dev": "ts-mocha src/**.spec.ts -w --watch-files 'src/**.ts'",
|
||||
"test": "ts-mocha src/**.spec.ts",
|
||||
"lint": "eslint src/*",
|
||||
"build": "rm -rf ./lib && tsc --build ./tsconfig.amd.json ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json ./tsconfig.umd.json",
|
||||
"prepublish": "npm run lint && npm run test && npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"russian",
|
||||
@@ -23,11 +39,17 @@
|
||||
"author": "anotherpit <anotherpit@gmail.com>",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"mocha": "^2.4.5",
|
||||
"typescript": "^2.0.10"
|
||||
"@types/mocha": "^10.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
||||
"@typescript-eslint/parser": "^6.8.0",
|
||||
"eslint": "^8.51.0",
|
||||
"mocha": "^10.2.0",
|
||||
"ts-mocha": "^10.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/anotherpit/numeralize-ru.git"
|
||||
"url": "git+https://github.com/anotherpit/numeralize-ru.git"
|
||||
}
|
||||
}
|
||||
|
||||
+1029
File diff suppressed because it is too large
Load Diff
+216
@@ -0,0 +1,216 @@
|
||||
export enum Gender {
|
||||
Masculine = 0,
|
||||
Feminine = 1,
|
||||
Neuter = 2
|
||||
}
|
||||
|
||||
export enum Case {
|
||||
Nominative = 0,
|
||||
Genitive = 1,
|
||||
Dative = 2,
|
||||
Accusative = 3,
|
||||
Instrumental = 4,
|
||||
Prepositional = 5
|
||||
}
|
||||
|
||||
const MINORS = [
|
||||
['ноль', 'нуля', 'нулю', 'ноль', 'нулём', 'нуле'],
|
||||
[
|
||||
['один', 'одна', 'одно'],
|
||||
['одного', 'одной', 'одного'],
|
||||
['одному', 'одной', 'одному'],
|
||||
[['одного', 'один'], 'одну', 'одно'],
|
||||
['одним', 'одной', 'одним'],
|
||||
['одном', 'одной', 'одном']
|
||||
],
|
||||
[
|
||||
['два', 'две', 'два'],
|
||||
'двух',
|
||||
'двум',
|
||||
[['двух', 'два'], ['двух', 'две'], 'два'],
|
||||
'двумя',
|
||||
'двух'
|
||||
],
|
||||
[
|
||||
'три',
|
||||
'трёх',
|
||||
'трём',
|
||||
[['трёх', 'три'], ['трёх', 'три'], 'три'],
|
||||
'тремя',
|
||||
'трёх'
|
||||
],
|
||||
[
|
||||
'четыре',
|
||||
'четырёх',
|
||||
'четырём',
|
||||
[['четырёх', 'четыре'], ['четырёх', 'четыре'], 'четыре'],
|
||||
'четырьмя',
|
||||
'четырёх'
|
||||
],
|
||||
['пять', 'пяти', 'пяти', 'пять', 'пятью', 'пяти'],
|
||||
['шесть', 'шести', 'шести', 'шесть', 'шестью', 'шести'],
|
||||
['семь', 'семи', 'семи', 'семь', 'семью', 'семи'],
|
||||
['восемь', 'восьми', 'восьми', 'восемь', 'восемью', 'восьми'],
|
||||
['девять', 'девяти', 'девяти', 'девять', 'девятью', 'девяти'],
|
||||
['десять', 'десяти', 'десяти', 'десять', 'десятью', 'десяти'],
|
||||
...['один', 'две', 'три', 'четыр', 'пят', 'шест', 'сем', 'восем', 'девят'].map((prefix) =>
|
||||
['надцать', 'надцати', 'надцати', 'надцать', 'надцатью', 'надцати'].map((suffix) =>
|
||||
`${prefix}${suffix}`
|
||||
)
|
||||
)
|
||||
] as const;
|
||||
|
||||
const TENS = [
|
||||
false,
|
||||
false,
|
||||
['двадцать', 'двадцати', 'двадцати', 'двадцать', 'двадцатью', 'двадцати'],
|
||||
['тридцать', 'тридцати', 'тридцати', 'тридцать', 'тридцатью', 'тридцати'],
|
||||
['сорок', 'сорока', 'сорока', 'сорок', 'сорока', 'сорока'],
|
||||
['пятьдесят', 'пятидесяти', 'пятидесяти', 'пятьдесят', 'пятьюдесятью', 'пятидесяти'],
|
||||
['шестьдесят', 'шестидесяти', 'шестидесяти', 'шестьдесят', 'шестьюдесятью', 'шестидесяти'],
|
||||
['семьдесят', 'семидесяти', 'семидесяти', 'семьдесят', 'семьюдесятью', 'семидесяти'],
|
||||
['восемьдесят', 'восьмидесяти', 'восьмидесяти', 'восемьдесят', 'восемьюдесятью', 'восьмидесяти'],
|
||||
['девяносто', 'девяноста', 'девяноста', 'девяносто', 'девяноста', 'девяноста']
|
||||
] as const;
|
||||
|
||||
const HUNDREDS = [
|
||||
false,
|
||||
['сто', 'ста', 'ста', 'сто', 'ста', 'ста'],
|
||||
['двести', 'двухсот', 'двумстам', 'двести', 'двумястами', 'двухстах'],
|
||||
['триста', 'трёхсот', 'трёмстам', 'триста', 'тремястами', 'трёхстах'],
|
||||
['четыреста', 'четырёхсот', 'четырёмстам', 'четыреста', 'четырьмястами', 'четырёхстах'],
|
||||
['пятьсот', 'пятисот', 'пятистам', 'пятьсот', 'пятьюстами', 'пятистах'],
|
||||
['шестьсот', 'шестисот', 'шестистам', 'шестьсот', 'шестьюстами', 'шестистах'],
|
||||
['семьсот', 'семисот', 'семистам', 'семьсот', 'семьюстами', 'семистах'],
|
||||
['восемьсот', 'восьмисот', 'восьмистам', 'восемьсот', 'восемьюстами', 'восьмистах'],
|
||||
['девятьсот', 'девятисот', 'девятистам', 'девятьсот', 'девятьюстами', 'девятистах']
|
||||
] as const;
|
||||
|
||||
const LARGES = [
|
||||
false,
|
||||
[
|
||||
Gender.Feminine,
|
||||
['тысяча', 'тысячи', 'тысяч'],
|
||||
['тысячи', 'тысяч', 'тысяч'],
|
||||
['тысяче', 'тысячам', 'тысячам'],
|
||||
['тысячу', 'тысячи', 'тысяч'],
|
||||
['тысячей', 'тысячами', 'тысячами'],
|
||||
['тысяче', 'тысячах', 'тысячах']
|
||||
],
|
||||
...['миллион', 'миллиард', 'триллион'].map<[Gender, ...string[][]]>((base) =>
|
||||
[
|
||||
Gender.Masculine,
|
||||
...[
|
||||
['', 'а', 'ов'],
|
||||
['а', 'ов', 'ов'],
|
||||
['у', 'ам', 'ам'],
|
||||
['', 'а', 'ов'],
|
||||
['ом', 'ами', 'ами'],
|
||||
['е', 'ах', 'ах']
|
||||
].map((kase) => kase.map((suffix) => `${base}${suffix}`))
|
||||
]
|
||||
)
|
||||
] as const;
|
||||
|
||||
/**
|
||||
* Pluralize noun according to count, e.g. `pluralize(42, 'рубль', 'рубля', 'рублей')`
|
||||
*/
|
||||
export function pluralize(count: number, one: string, two: string, five: string): string {
|
||||
count = Math.floor(Math.abs(count)) % 100;
|
||||
if (count > 10 && count < 20) {
|
||||
return five;
|
||||
}
|
||||
count = count % 10;
|
||||
if (1 === count) {
|
||||
return one;
|
||||
}
|
||||
if (count >= 2 && count <= 4) {
|
||||
return two;
|
||||
}
|
||||
return five;
|
||||
}
|
||||
|
||||
function small(number: number, gender: Gender, kase: Case, animate: boolean): string {
|
||||
// Zero
|
||||
if (0 === number) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Collect chunks
|
||||
const result: string[] = [];
|
||||
|
||||
// Hundreds
|
||||
const hundreds = HUNDREDS[Math.floor(number / 100)];
|
||||
if (hundreds) {
|
||||
result.push(hundreds[kase]);
|
||||
}
|
||||
|
||||
// Tens
|
||||
const tens = TENS[Math.floor(number % 100 / 10)];
|
||||
if (tens) {
|
||||
result.push(tens[kase]);
|
||||
}
|
||||
|
||||
// Minors
|
||||
let minors = number % 100;
|
||||
if (minors >= MINORS.length) {
|
||||
minors = number % 10;
|
||||
}
|
||||
if (minors) {
|
||||
let part;
|
||||
if (
|
||||
((part = MINORS[minors][kase]) && typeof part === 'string')
|
||||
|| ((part = MINORS[minors][kase][gender]) && typeof part === 'string')
|
||||
|| (part = MINORS[minors][kase][gender][animate ? 0 : 1])
|
||||
) {
|
||||
result.push(part)
|
||||
}
|
||||
}
|
||||
|
||||
// Return
|
||||
return result.join(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeralize number
|
||||
*/
|
||||
export function numeralize(
|
||||
number: number,
|
||||
gender: Gender = Gender.Masculine,
|
||||
kase: Case = Case.Nominative,
|
||||
animate: boolean = false
|
||||
): string {
|
||||
// Normalize params
|
||||
number = Math.abs(parseInt(String(number), 10));
|
||||
|
||||
// Collect chunks
|
||||
const result: string[] = [];
|
||||
|
||||
// Descend known powers of thousand
|
||||
for (let l = LARGES.length, i = l; i >= 0; i--) {
|
||||
const base = Math.pow(10, i * 3);
|
||||
const current = Math.floor(number / base);
|
||||
number = number % base;
|
||||
|
||||
if (current) {
|
||||
const large = i ? LARGES[i] : null;
|
||||
const numeral = small(current, large ? large[0] : gender, kase, large ? false : animate);
|
||||
if (numeral) {
|
||||
result.push(numeral);
|
||||
if (large) {
|
||||
const [, ...forms] = large
|
||||
const plural = pluralize(current, forms[kase][0], forms[kase][1], forms[kase][2]);
|
||||
result.push(plural);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zero
|
||||
if (!result.length) {
|
||||
result.push(MINORS[0][kase]);
|
||||
}
|
||||
|
||||
// Return
|
||||
return result.join(' ');
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import * as numeralize from '../index';
|
||||
|
||||
let g: numeralize.Gender;
|
||||
g = numeralize.GENDER_MASCULINE;
|
||||
g = numeralize.GENDER_FEMININE;
|
||||
g = numeralize.GENDER_NEUTER;
|
||||
|
||||
let c: numeralize.Case;
|
||||
c = numeralize.CASE_NOMINATIVE;
|
||||
c = numeralize.CASE_GENITIVE;
|
||||
c = numeralize.CASE_DATIVE;
|
||||
c = numeralize.CASE_ACCUSATIVE;
|
||||
c = numeralize.CASE_INSTRUMENTAL;
|
||||
c = numeralize.CASE_PREPOSITIONAL;
|
||||
|
||||
let s: string;
|
||||
s = numeralize(123, g, c, true);
|
||||
s = numeralize.pluralize(123, 'рубль', 'рубля', 'рублей');
|
||||
|
||||
-1078
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "umd",
|
||||
"outDir": "./lib/amd/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "./lib/cjs/"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "es2020",
|
||||
"outDir": "./lib/esm/"
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es3",
|
||||
/* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "NodeNext",
|
||||
/* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
"types": ["node", "mocha"], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
"declaration": false,
|
||||
/* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true,
|
||||
/* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
/* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true,
|
||||
/* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true
|
||||
/* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"include": ["./src/index.ts"]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib/types",
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "umd",
|
||||
"outDir": "./lib/umd/"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user