@wise-old-man/utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/metrics.ts ADDED
@@ -0,0 +1,267 @@
1
+ import { mapValues } from 'lodash';
2
+
3
+ enum Skill {
4
+ OVERALL = 'overall',
5
+ ATTACK = 'attack',
6
+ DEFENCE = 'defence',
7
+ STRENGTH = 'strength',
8
+ HITPOINTS = 'hitpoints',
9
+ RANGED = 'ranged',
10
+ PRAYER = 'prayer',
11
+ MAGIC = 'magic',
12
+ COOKING = 'cooking',
13
+ WOODCUTTING = 'woodcutting',
14
+ FLETCHING = 'fletching',
15
+ FISHING = 'fishing',
16
+ FIREMAKING = 'firemaking',
17
+ CRAFTING = 'crafting',
18
+ SMITHING = 'smithing',
19
+ MINING = 'mining',
20
+ HERBLORE = 'herblore',
21
+ AGILITY = 'agility',
22
+ THIEVING = 'thieving',
23
+ SLAYER = 'slayer',
24
+ FARMING = 'farming',
25
+ RUNECRAFTING = 'runecrafting',
26
+ HUNTER = 'hunter',
27
+ CONSTRUCTION = 'construction'
28
+ }
29
+
30
+ enum Boss {
31
+ ABYSSAL_SIRE = 'abyssal_sire',
32
+ ALCHEMICAL_HYDRA = 'alchemical_hydra',
33
+ BARROWS_CHESTS = 'barrows_chests',
34
+ BRYOPHYTA = 'bryophyta',
35
+ CALLISTO = 'callisto',
36
+ CERBERUS = 'cerberus',
37
+ CHAMBERS_OF_XERIC = 'chambers_of_xeric',
38
+ CHAMBERS_OF_XERIC_CM = 'chambers_of_xeric_challenge_mode',
39
+ CHAOS_ELEMENTAL = 'chaos_elemental',
40
+ CHAOS_FANATIC = 'chaos_fanatic',
41
+ COMMANDER_ZILYANA = 'commander_zilyana',
42
+ CORPOREAL_BEAST = 'corporeal_beast',
43
+ CRAZY_ARCHAEOLOGIST = 'crazy_archaeologist',
44
+ DAGANNOTH_PRIME = 'dagannoth_prime',
45
+ DAGANNOTH_REX = 'dagannoth_rex',
46
+ DAGANNOTH_SUPREME = 'dagannoth_supreme',
47
+ DERANGED_ARCHAEOLOGIST = 'deranged_archaeologist',
48
+ GENERAL_GRAARDOR = 'general_graardor',
49
+ GIANT_MOLE = 'giant_mole',
50
+ GROTESQUE_GUARDIANS = 'grotesque_guardians',
51
+ HESPORI = 'hespori',
52
+ KALPHITE_QUEEN = 'kalphite_queen',
53
+ KING_BLACK_DRAGON = 'king_black_dragon',
54
+ KRAKEN = 'kraken',
55
+ KREEARRA = 'kreearra',
56
+ KRIL_TSUTSAROTH = 'kril_tsutsaroth',
57
+ MIMIC = 'mimic',
58
+ NIGHTMARE = 'nightmare',
59
+ PHOSANIS_NIGHTMARE = 'phosanis_nightmare',
60
+ OBOR = 'obor',
61
+ SARACHNIS = 'sarachnis',
62
+ SCORPIA = 'scorpia',
63
+ SKOTIZO = 'skotizo',
64
+ TEMPOROSS = 'tempoross',
65
+ THE_GAUNTLET = 'the_gauntlet',
66
+ THE_CORRUPTED_GAUNTLET = 'the_corrupted_gauntlet',
67
+ THEATRE_OF_BLOOD = 'theatre_of_blood',
68
+ THEATRE_OF_BLOOD_HARD_MODE = 'theatre_of_blood_hard_mode',
69
+ THERMONUCLEAR_SMOKE_DEVIL = 'thermonuclear_smoke_devil',
70
+ TZKAL_ZUK = 'tzkal_zuk',
71
+ TZTOK_JAD = 'tztok_jad',
72
+ VENENATIS = 'venenatis',
73
+ VETION = 'vetion',
74
+ VORKATH = 'vorkath',
75
+ WINTERTODT = 'wintertodt',
76
+ ZALCANO = 'zalcano',
77
+ ZULRAH = 'zulrah'
78
+ }
79
+
80
+ enum Activity {
81
+ LEAGUE_POINTS = 'league_points',
82
+ BOUNTY_HUNTER_HUNTER = 'bounty_hunter_hunter',
83
+ BOUNTY_HUNTER_ROGUE = 'bounty_hunter_rogue',
84
+ CLUE_SCROLLS_ALL = 'clue_scrolls_all',
85
+ CLUE_SCROLLS_BEGINNER = 'clue_scrolls_beginner',
86
+ CLUE_SCROLLS_EASY = 'clue_scrolls_easy',
87
+ CLUE_SCROLLS_MEDIUM = 'clue_scrolls_medium',
88
+ CLUE_SCROLLS_HARD = 'clue_scrolls_hard',
89
+ CLUE_SCROLLS_ELITE = 'clue_scrolls_elite',
90
+ CLUE_SCROLLS_MASTER = 'clue_scrolls_master',
91
+ LAST_MAN_STANDING = 'last_man_standing',
92
+ SOUL_WARS_ZEAL = 'soul_wars_zeal'
93
+ }
94
+
95
+ enum VirtualMetric {
96
+ EHP = 'ehp',
97
+ EHB = 'ehb'
98
+ }
99
+
100
+ enum MetricType {
101
+ SKILL = 'skill',
102
+ BOSS = 'boss',
103
+ ACTIVITY = 'activity',
104
+ VIRTUAL = 'virtual'
105
+ }
106
+
107
+ enum MetricMeasure {
108
+ EXPERIENCE = 'experience',
109
+ KILLS = 'kills',
110
+ SCORE = 'score',
111
+ VALUE = 'value'
112
+ }
113
+
114
+ const SkillProps = mapValues(
115
+ {
116
+ [Skill.OVERALL]: { name: 'Overall', isCombat: false, isMembers: false },
117
+ [Skill.ATTACK]: { name: 'Attack', isCombat: true, isMembers: false },
118
+ [Skill.DEFENCE]: { name: 'Defence', isCombat: true, isMembers: false },
119
+ [Skill.STRENGTH]: { name: 'Strength', isCombat: true, isMembers: false },
120
+ [Skill.HITPOINTS]: { name: 'Hitpoints', isCombat: true, isMembers: false },
121
+ [Skill.RANGED]: { name: 'Ranged', isCombat: true, isMembers: false },
122
+ [Skill.PRAYER]: { name: 'Prayer', isCombat: true, isMembers: false },
123
+ [Skill.MAGIC]: { name: 'Magic', isCombat: true, isMembers: false },
124
+ [Skill.COOKING]: { name: 'Cooking', isCombat: false, isMembers: false },
125
+ [Skill.WOODCUTTING]: { name: 'Woodcutting', isCombat: false, isMembers: false },
126
+ [Skill.FLETCHING]: { name: 'Fletching', isCombat: false, isMembers: true },
127
+ [Skill.FISHING]: { name: 'Fishing', isCombat: false, isMembers: false },
128
+ [Skill.FIREMAKING]: { name: 'Firemaking', isCombat: false, isMembers: false },
129
+ [Skill.CRAFTING]: { name: 'Crafting', isCombat: false, isMembers: false },
130
+ [Skill.SMITHING]: { name: 'Smithing', isCombat: false, isMembers: false },
131
+ [Skill.MINING]: { name: 'Mining', isCombat: false, isMembers: false },
132
+ [Skill.HERBLORE]: { name: 'Herblore', isCombat: false, isMembers: true },
133
+ [Skill.AGILITY]: { name: 'Agility', isCombat: false, isMembers: true },
134
+ [Skill.THIEVING]: { name: 'Thieving', isCombat: false, isMembers: true },
135
+ [Skill.SLAYER]: { name: 'Slayer', isCombat: false, isMembers: true },
136
+ [Skill.FARMING]: { name: 'Farming', isCombat: false, isMembers: true },
137
+ [Skill.RUNECRAFTING]: { name: 'Runecrafting', isCombat: false, isMembers: false },
138
+ [Skill.HUNTER]: { name: 'Hunter', isCombat: false, isMembers: true },
139
+ [Skill.CONSTRUCTION]: { name: 'Construction', isCombat: false, isMembers: false }
140
+ },
141
+ (props, key) => ({ ...props, key, type: MetricType.SKILL, measure: MetricMeasure.EXPERIENCE })
142
+ );
143
+
144
+ const BossProps = mapValues(
145
+ {
146
+ [Boss.ABYSSAL_SIRE]: { name: 'Abyssal Sire', minimumKc: 50, isMembers: true },
147
+ [Boss.ALCHEMICAL_HYDRA]: { name: 'Alchemical Hydra', minimumKc: 50, isMembers: true },
148
+ [Boss.BARROWS_CHESTS]: { name: 'Barrows Chests', minimumKc: 50, isMembers: true },
149
+ [Boss.BRYOPHYTA]: { name: 'Bryophyta', minimumKc: 10, isMembers: false },
150
+ [Boss.CALLISTO]: { name: 'Callisto', minimumKc: 50, isMembers: true },
151
+ [Boss.CERBERUS]: { name: 'Cerberus', minimumKc: 50, isMembers: true },
152
+ [Boss.CHAMBERS_OF_XERIC]: { name: 'Chambers Of Xeric', minimumKc: 50, isMembers: true },
153
+ [Boss.CHAMBERS_OF_XERIC_CM]: { name: 'Chambers Of Xeric (CM)', minimumKc: 10, isMembers: true },
154
+ [Boss.CHAOS_ELEMENTAL]: { name: 'Chaos Elemental', minimumKc: 50, isMembers: true },
155
+ [Boss.CHAOS_FANATIC]: { name: 'Chaos Fanatic', minimumKc: 50, isMembers: true },
156
+ [Boss.COMMANDER_ZILYANA]: { name: 'Commander Zilyana', minimumKc: 50, isMembers: true },
157
+ [Boss.CORPOREAL_BEAST]: { name: 'Corporeal Beast', minimumKc: 50, isMembers: true },
158
+ [Boss.CRAZY_ARCHAEOLOGIST]: { name: 'Crazy Archaeologist', minimumKc: 50, isMembers: true },
159
+ [Boss.DAGANNOTH_PRIME]: { name: 'Dagannoth Prime', minimumKc: 50, isMembers: true },
160
+ [Boss.DAGANNOTH_REX]: { name: 'Dagannoth Rex', minimumKc: 50, isMembers: true },
161
+ [Boss.DAGANNOTH_SUPREME]: { name: 'Dagannoth Supreme', minimumKc: 50, isMembers: true },
162
+ [Boss.DERANGED_ARCHAEOLOGIST]: { name: 'Deranged Archaeologist', minimumKc: 50, isMembers: true },
163
+ [Boss.GENERAL_GRAARDOR]: { name: 'General Graardor', minimumKc: 50, isMembers: true },
164
+ [Boss.GIANT_MOLE]: { name: 'Giant Mole', minimumKc: 50, isMembers: true },
165
+ [Boss.GROTESQUE_GUARDIANS]: { name: 'Grotesque Guardians', minimumKc: 50, isMembers: true },
166
+ [Boss.HESPORI]: { name: 'Hespori', minimumKc: 10, isMembers: true },
167
+ [Boss.KALPHITE_QUEEN]: { name: 'Kalphite Queen', minimumKc: 50, isMembers: true },
168
+ [Boss.KING_BLACK_DRAGON]: { name: 'King Black Dragon', minimumKc: 50, isMembers: true },
169
+ [Boss.KRAKEN]: { name: 'Kraken', minimumKc: 50, isMembers: true },
170
+ [Boss.KREEARRA]: { name: "Kree'Arra", minimumKc: 50, isMembers: true },
171
+ [Boss.KRIL_TSUTSAROTH]: { name: "K'ril Tsutsaroth", minimumKc: 50, isMembers: true },
172
+ [Boss.MIMIC]: { name: 'Mimic', minimumKc: 2, isMembers: true },
173
+ [Boss.NIGHTMARE]: { name: 'Nightmare', minimumKc: 50, isMembers: true },
174
+ [Boss.PHOSANIS_NIGHTMARE]: { name: "Phosani's Nightmare", minimumKc: 50, isMembers: true },
175
+ [Boss.OBOR]: { name: 'Obor', minimumKc: 10, isMembers: false },
176
+ [Boss.SARACHNIS]: { name: 'Sarachnis', minimumKc: 50, isMembers: true },
177
+ [Boss.SCORPIA]: { name: 'Scorpia', minimumKc: 50, isMembers: true },
178
+ [Boss.SKOTIZO]: { name: 'Skotizo', minimumKc: 10, isMembers: true },
179
+ [Boss.TEMPOROSS]: { name: 'Tempoross', minimumKc: 50, isMembers: true },
180
+ [Boss.THE_GAUNTLET]: { name: 'The Gauntlet', minimumKc: 50, isMembers: true },
181
+ [Boss.THE_CORRUPTED_GAUNTLET]: { name: 'The Corrupted Gauntlet', minimumKc: 10, isMembers: true },
182
+ [Boss.THEATRE_OF_BLOOD]: { name: 'Theatre Of Blood', minimumKc: 50, isMembers: true },
183
+ [Boss.THEATRE_OF_BLOOD_HARD_MODE]: { name: 'Theatre Of Blood (HM)', minimumKc: 50, isMembers: true },
184
+ [Boss.THERMONUCLEAR_SMOKE_DEVIL]: { name: 'Thermonuclear Smoke Devil', minimumKc: 50, isMembers: true },
185
+ [Boss.TZKAL_ZUK]: { name: 'TzKal-Zuk', minimumKc: 2, isMembers: true },
186
+ [Boss.TZTOK_JAD]: { name: 'TzTok-Jad', minimumKc: 10, isMembers: true },
187
+ [Boss.VENENATIS]: { name: 'Venenatis', minimumKc: 50, isMembers: true },
188
+ [Boss.VETION]: { name: "Vet'ion", minimumKc: 50, isMembers: true },
189
+ [Boss.VORKATH]: { name: 'Vorkath', minimumKc: 50, isMembers: true },
190
+ [Boss.WINTERTODT]: { name: 'Wintertodt', minimumKc: 50, isMembers: true },
191
+ [Boss.ZALCANO]: { name: 'Zalcano', minimumKc: 50, isMembers: true },
192
+ [Boss.ZULRAH]: { name: 'Zulrah', minimumKc: 50, isMembers: true }
193
+ },
194
+ (props, key) => ({ ...props, key, type: MetricType.BOSS, measure: MetricMeasure.KILLS })
195
+ );
196
+
197
+ const ActivityProps = mapValues(
198
+ {
199
+ [Activity.LEAGUE_POINTS]: { name: 'League Points' },
200
+ [Activity.BOUNTY_HUNTER_HUNTER]: { name: 'Bounty Hunter (Hunter)' },
201
+ [Activity.BOUNTY_HUNTER_ROGUE]: { name: 'Bounty Hunter (Rogue)' },
202
+ [Activity.CLUE_SCROLLS_ALL]: { name: 'Clue Scrolls (All)' },
203
+ [Activity.CLUE_SCROLLS_BEGINNER]: { name: 'Clue Scrolls (Beginner)' },
204
+ [Activity.CLUE_SCROLLS_EASY]: { name: 'Clue Scrolls (Easy)' },
205
+ [Activity.CLUE_SCROLLS_MEDIUM]: { name: 'Clue Scrolls (Medium)' },
206
+ [Activity.CLUE_SCROLLS_HARD]: { name: 'Clue Scrolls (Hard)' },
207
+ [Activity.CLUE_SCROLLS_ELITE]: { name: 'Clue Scrolls (Elite)' },
208
+ [Activity.CLUE_SCROLLS_MASTER]: { name: 'Clue Scrolls (Master)' },
209
+ [Activity.LAST_MAN_STANDING]: { name: 'Last Man Standing' },
210
+ [Activity.SOUL_WARS_ZEAL]: { name: 'Soul Wars Zeal' }
211
+ },
212
+ (props, key) => ({ ...props, key, type: MetricType.ACTIVITY, measure: MetricMeasure.SCORE })
213
+ );
214
+
215
+ const VirtualMetricProps = mapValues(
216
+ {
217
+ [VirtualMetric.EHP]: { name: 'EHP' },
218
+ [VirtualMetric.EHB]: { name: 'EHB' }
219
+ },
220
+ (props, key) => ({ ...props, key, type: MetricType.VIRTUAL, measure: MetricMeasure.VALUE })
221
+ );
222
+
223
+ const Metrics = {
224
+ ...Skill,
225
+ ...Boss,
226
+ ...Activity,
227
+ ...VirtualMetric
228
+ };
229
+
230
+ const MetricProps = {
231
+ ...SkillProps,
232
+ ...BossProps,
233
+ ...ActivityProps,
234
+ ...VirtualMetricProps
235
+ };
236
+
237
+ type Metric = Skill | Boss | Activity | VirtualMetric;
238
+
239
+ const SKILLS = Object.values(Skill);
240
+ const BOSSES = Object.values(Boss);
241
+ const ACTIVITIES = Object.values(Activity);
242
+ const VIRTUAL_METRICS = Object.values(VirtualMetric);
243
+
244
+ function findMetric(metricName: string): Metric | null {
245
+ for (var [key, value] of Object.entries(MetricProps)) {
246
+ if (value.name === metricName) return key as Metric;
247
+ }
248
+
249
+ return null;
250
+ }
251
+
252
+ export {
253
+ // Types
254
+ Metric,
255
+ // Enums
256
+ Metrics,
257
+ MetricProps,
258
+ MetricType,
259
+ MetricMeasure,
260
+ // Lists
261
+ SKILLS,
262
+ BOSSES,
263
+ ACTIVITIES,
264
+ VIRTUAL_METRICS,
265
+ // Functions
266
+ findMetric
267
+ };
package/src/numbers.ts ADDED
@@ -0,0 +1,5 @@
1
+ function round(num: number, cases: number) {
2
+ return Math.round(num * Math.pow(10, cases)) / Math.pow(10, cases);
3
+ }
4
+
5
+ export { round };
package/src/periods.ts ADDED
@@ -0,0 +1,57 @@
1
+ const CUSTOM_PERIOD_REGEX = /(\d+y)?(\d+m)?(\d+w)?(\d+d)?(\d+h)?/;
2
+
3
+ enum Period {
4
+ FIVE_MIN = '5min',
5
+ DAY = 'day',
6
+ WEEK = 'week',
7
+ MONTH = 'month',
8
+ YEAR = 'year'
9
+ }
10
+
11
+ const PeriodProps = {
12
+ [Period.FIVE_MIN]: { name: '5 Min', milliseconds: 300_000 },
13
+ [Period.DAY]: { name: 'Day', milliseconds: 86_400_000 },
14
+ [Period.WEEK]: { name: 'Week', milliseconds: 604_800_000 },
15
+ [Period.MONTH]: { name: 'Month', milliseconds: 2_678_400_000 },
16
+ [Period.YEAR]: { name: 'Year', milliseconds: 31_556_926_000 }
17
+ };
18
+
19
+ const PERIODS = Object.values(Period);
20
+
21
+ function findPeriod(periodName: string): Period | null {
22
+ for (var [key, value] of Object.entries(PeriodProps)) {
23
+ if (value.name === periodName) return key as Period;
24
+ }
25
+
26
+ return null;
27
+ }
28
+
29
+ function parsePeriodExpression(periodExpression: string): [string, number] | null {
30
+ const fixed = periodExpression.toLowerCase();
31
+
32
+ if (PERIODS.includes(fixed as any)) {
33
+ return [fixed, PeriodProps[fixed].milliseconds];
34
+ }
35
+
36
+ const result = fixed.match(CUSTOM_PERIOD_REGEX);
37
+
38
+ if (!result || result.length === 0 || result[0] !== fixed) return null;
39
+
40
+ const years = result[1] ? parseInt(result[1].replace(/\D/g, '')) : null;
41
+ const months = result[2] ? parseInt(result[2].replace(/\D/g, '')) : null;
42
+ const weeks = result[3] ? parseInt(result[3].replace(/\D/g, '')) : null;
43
+ const days = result[4] ? parseInt(result[4].replace(/\D/g, '')) : null;
44
+ const hours = result[5] ? parseInt(result[5].replace(/\D/g, '')) : null;
45
+
46
+ const yearsMs = years ? years * PeriodProps[Period.YEAR].milliseconds : 0;
47
+ const monthsMs = months ? months * PeriodProps[Period.MONTH].milliseconds : 0;
48
+ const weeksMs = weeks ? weeks * PeriodProps[Period.WEEK].milliseconds : 0;
49
+ const daysMs = days ? days * PeriodProps[Period.DAY].milliseconds : 0;
50
+ const hoursMs = hours ? hours * (PeriodProps[Period.DAY].milliseconds / 24) : 0;
51
+
52
+ const totalMs = yearsMs + monthsMs + weeksMs + daysMs + hoursMs;
53
+
54
+ return [result[0], totalMs];
55
+ }
56
+
57
+ export { Period, PeriodProps, PERIODS, findPeriod, parsePeriodExpression };
package/src/players.ts ADDED
@@ -0,0 +1,76 @@
1
+ enum PlayerType {
2
+ UNKNOWN = 'unknown',
3
+ REGULAR = 'regular',
4
+ IRONMAN = 'ironman',
5
+ ULTIMATE = 'ultimate',
6
+ HARDCORE = 'hardcore'
7
+ }
8
+
9
+ enum PlayerBuild {
10
+ MAIN = 'main',
11
+ F2P = 'f2p',
12
+ LVL3 = 'lvl3',
13
+ ZERKER = 'zerker',
14
+ DEF1 = '1def',
15
+ HP10 = '10hp'
16
+ }
17
+
18
+ const PlayerTypeProps = {
19
+ [PlayerType.UNKNOWN]: { name: 'Unknown' },
20
+ [PlayerType.REGULAR]: { name: 'Regular' },
21
+ [PlayerType.IRONMAN]: { name: 'Ironman' },
22
+ [PlayerType.ULTIMATE]: { name: 'Ultimate' },
23
+ [PlayerType.HARDCORE]: { name: 'Hardcore' }
24
+ };
25
+
26
+ const PlayerBuildProps = {
27
+ [PlayerBuild.MAIN]: { name: 'Main' },
28
+ [PlayerBuild.F2P]: { name: 'F2P' },
29
+ [PlayerBuild.LVL3]: { name: 'Level 3' },
30
+ [PlayerBuild.ZERKER]: { name: 'Zerker Pure' },
31
+ [PlayerBuild.DEF1]: { name: '1 Defence Pure' },
32
+ [PlayerBuild.HP10]: { name: '10 Hitpoints Pure' }
33
+ };
34
+
35
+ const PLAYER_TYPES = Object.values(PlayerType);
36
+ const PLAYER_BUILDS = Object.values(PlayerBuild);
37
+
38
+ function findPlayerType(typeName: string): PlayerType | null {
39
+ for (var [key, value] of Object.entries(PlayerTypeProps)) {
40
+ if (value.name === typeName) return key as PlayerType;
41
+ }
42
+
43
+ return null;
44
+ }
45
+
46
+ function findPlayerBuild(buildName: string): PlayerBuild | null {
47
+ for (var [key, value] of Object.entries(PlayerBuildProps)) {
48
+ if (value.name === buildName) return key as PlayerBuild;
49
+ }
50
+
51
+ return null;
52
+ }
53
+
54
+ function standardizeUsername(username) {
55
+ return sanitizeUsername(username).toLowerCase();
56
+ }
57
+
58
+ function sanitizeUsername(username) {
59
+ return username.replace(/[-_\s]/g, ' ').trim();
60
+ }
61
+
62
+ export {
63
+ // Enums
64
+ PlayerType,
65
+ PlayerBuild,
66
+ PlayerTypeProps,
67
+ PlayerBuildProps,
68
+ // Lists
69
+ PLAYER_TYPES,
70
+ PLAYER_BUILDS,
71
+ // Functions
72
+ findPlayerType,
73
+ findPlayerBuild,
74
+ sanitizeUsername,
75
+ standardizeUsername
76
+ };
package/src/strings.ts ADDED
@@ -0,0 +1,34 @@
1
+ export function capitalize(string: string | null): string | null {
2
+ if (!string) return null;
3
+ return string.charAt(0).toUpperCase() + string.slice(1);
4
+ }
5
+
6
+ export function formatNumber(num: number, withLetters = false) {
7
+ if (num === undefined || num === null) return -1;
8
+
9
+ // If number is float
10
+ if (num % 1 !== 0) {
11
+ return (Math.round(num * 100) / 100).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
12
+ }
13
+
14
+ if ((num < 10000 && num > -10000) || !withLetters) {
15
+ return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,');
16
+ }
17
+
18
+ // < 10 million
19
+ if (num < 10_000_000 && num > -10_000_000) {
20
+ return `${Math.floor(num / 1000)}k`;
21
+ }
22
+
23
+ // < 1 billion
24
+ if (num < 1_000_000_000 && num > -1_000_000_000) {
25
+ return `${Math.round((num / 1000000 + Number.EPSILON) * 100) / 100}m`;
26
+ }
27
+
28
+ return `${Math.round((num / 1000000000 + Number.EPSILON) * 100) / 100}b`;
29
+ }
30
+
31
+ export function padNumber(value: number): string {
32
+ if (!value) return '00';
33
+ return value < 10 ? `0${value}` : value.toString();
34
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["es6", "dom", "es2017"],
4
+ "target": "es5",
5
+ "module": "commonjs",
6
+ "esModuleInterop": true,
7
+ "noImplicitAny": false,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "outDir": "dist",
12
+ "sourceMap": true,
13
+ "declaration": true
14
+ },
15
+ "exclude": ["node_modules", "dist"]
16
+ }