Compare commits

...

14 Commits

Author SHA1 Message Date
maxswa
7de2d9a95a v2.2.0 2020-07-23 18:22:38 -04:00
Max Swartwout
a143306519 Merge pull request #15 from maxswa/release/2.2.0
Release/2.2.0
2020-07-23 18:20:49 -04:00
maxswa
86b81abfd8 Upgrade dependencies. 2020-07-23 18:18:58 -04:00
maxswa
8d065742d0 Replace cheerio with jsdom. 2020-07-23 18:13:51 -04:00
Max
eaa3d4a299 v2.1.0 2020-04-01 00:30:08 -04:00
Max Swartwout
a92fa7fffe Merge pull request #10 from maxswa/release/1.2.2
Release/1.2.2
2020-04-01 00:27:54 -04:00
Max
90f2939761 Upgrade dependencies, fix tests. 2020-04-01 00:23:56 -04:00
Max
12046246ef Add nightmare to boss list. 2020-04-01 00:23:37 -04:00
Max Swartwout
adf73e59c4 Merge pull request #9 from maxswa/dependabot/npm_and_yarn/acorn-5.7.4
Bump acorn from 5.7.3 to 5.7.4
2020-03-31 23:53:56 -04:00
dependabot[bot]
f2fcbad1c4 Bump acorn from 5.7.3 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-01 03:53:20 +00:00
Max Swartwout
0f47310814 Merge pull request #8 from maxswa/bug/rsn-format-error
Add catch for getRSNFormat error.
2020-03-31 23:52:30 -04:00
maxswa
30530fde01 Add catch for getRSNFormat error. 2020-01-29 12:24:59 -05:00
maxswa
2c0268939d v2.0.2 2020-01-06 21:54:21 -05:00
maxswa
0142783d43 Remove temporary bosses fix. 2020-01-06 21:53:50 -05:00
9 changed files with 886 additions and 832 deletions

View File

@@ -146,6 +146,7 @@ Activities consist of all levels of clue scrolls as well as minigames and bosses
| Kreearra | `kreeArra` | | Kreearra | `kreeArra` |
| K'ril Tsutsaroth | `krilTsutsaroth` | | K'ril Tsutsaroth | `krilTsutsaroth` |
| Mimic | `mimic` | | Mimic | `mimic` |
| The Nightmare of Ashihama | `nightmare` |
| Obor | `obor` | | Obor | `obor` |
| Sarachnis | `sarachnis` | | Sarachnis | `sarachnis` |
| Scorpia | `scorpia` | | Scorpia | `scorpia` |

View File

@@ -8,169 +8,173 @@ import {
} from '../src/index'; } from '../src/index';
test('Parse CSV to json', () => { test('Parse CSV to json', () => {
const csv = `40258,2063,218035714 const csv = `246,2277,1338203419
20554, 99, 21102621 615,99,77438259
39059, 99, 15364425 428,99,69176307
14245, 99, 26556827 425,99,115218641
19819, 99, 33511407 138,99,181425111
27857, 99, 25774115 160,99,169725807
44278, 91, 6081159 97,99,50666171
40110, 99, 15128024 144,99,93155913
178948, 90, 5347474 2108,99,53198880
175463, 81, 2355494 5750,99,19589494
138677, 90, 5356303 295,99,76386488
77587, 91, 5904710 1304,99,32252994
158478, 85, 3570485 847,99,54325931
93958, 83, 2684426 534,99,26379932
39179, 88, 4425107 7213,99,13246799
138406, 77, 1591377 2475,99,18161285
33399, 90, 5866307 1837,99,14746134
1794, 99, 15057674 668,99,23961670
45551, 91, 6363261 3841,99,17970837
121165, 90, 5748493 265,99,56230978
89460, 88, 4624078 821,99,62123353
53099, 80, 2008229 169,99,43127930
169127, 73, 1067670 810,99,37688883
115543, 82, 2546048 92,99,32005622
-1, -1 -1,-1
-1, -1 -1,-1
-1, -1 -1,-1
24817, 476 32,12148
212728, 1 3105,76
94827, 20 1997,505
59099, 74 127,4259
24642, 231 361,915
5206, 99 392,250
6293, 51 1,6143
32875, 500 4814,898
374,2780 382,2780
934,3000 944,3000
1936,1452 1981,1452
4919,23 4981,23
101,4038 888,1046
152,334 613,4856
6153,133 102,4038
4501,250 156,334
6806,603 6240,133
4569,250
6893,603
1,17798 1,17798
9160,125 9320,125
1021,2802 1030,2802
4295,1655 4342,1655
959,2951 966,2951
10009,1 10151,1
1271,2407 1288,2407
378,4669 377,4669
543,1567 545,1567
6003,94 6083,94
263,2897 264,2897
4000,1277 4052,1277
41016,1477 41643,1477
617,2391 625,2391
120,2981 120,2981
1,109 1,109
3,22666
26,323 26,323
198,1101 201,1101
81,3404 82,3404
5027,61 5085,61
63,375 63,375
2845,6 2870,6
6913,138 6984,138
3999,2000 4043,2000
484,8 489,8
957,47 967,47
10987,223 11155,223
1923,272 1940,272
8484,1340 8623,1340
599,1694 605,1694
12489,435 -1,-1
3810,4583`; 3867,4583`;
const expectedOutput: Stats = { const expectedOutput: Stats = {
skills: { skills: {
overall: { rank: 40258, level: 2063, xp: 218035714 }, overall: { rank: 246, level: 2277, xp: 1338203419 },
attack: { rank: 20554, level: 99, xp: 21102621 }, attack: { rank: 615, level: 99, xp: 77438259 },
defence: { rank: 39059, level: 99, xp: 15364425 }, defence: { rank: 428, level: 99, xp: 69176307 },
strength: { rank: 14245, level: 99, xp: 26556827 }, strength: { rank: 425, level: 99, xp: 115218641 },
hitpoints: { rank: 19819, level: 99, xp: 33511407 }, hitpoints: { rank: 138, level: 99, xp: 181425111 },
ranged: { rank: 27857, level: 99, xp: 25774115 }, ranged: { rank: 160, level: 99, xp: 169725807 },
prayer: { rank: 44278, level: 91, xp: 6081159 }, prayer: { rank: 97, level: 99, xp: 50666171 },
magic: { rank: 40110, level: 99, xp: 15128024 }, magic: { rank: 144, level: 99, xp: 93155913 },
cooking: { rank: 178948, level: 90, xp: 5347474 }, cooking: { rank: 2108, level: 99, xp: 53198880 },
woodcutting: { rank: 175463, level: 81, xp: 2355494 }, woodcutting: { rank: 5750, level: 99, xp: 19589494 },
fletching: { rank: 138677, level: 90, xp: 5356303 }, fletching: { rank: 295, level: 99, xp: 76386488 },
fishing: { rank: 77587, level: 91, xp: 5904710 }, fishing: { rank: 1304, level: 99, xp: 32252994 },
firemaking: { rank: 158478, level: 85, xp: 3570485 }, firemaking: { rank: 847, level: 99, xp: 54325931 },
crafting: { rank: 93958, level: 83, xp: 2684426 }, crafting: { rank: 534, level: 99, xp: 26379932 },
smithing: { rank: 39179, level: 88, xp: 4425107 }, smithing: { rank: 7213, level: 99, xp: 13246799 },
mining: { rank: 138406, level: 77, xp: 1591377 }, mining: { rank: 2475, level: 99, xp: 18161285 },
herblore: { rank: 33399, level: 90, xp: 5866307 }, herblore: { rank: 1837, level: 99, xp: 14746134 },
agility: { rank: 1794, level: 99, xp: 15057674 }, agility: { rank: 668, level: 99, xp: 23961670 },
thieving: { rank: 45551, level: 91, xp: 6363261 }, thieving: { rank: 3841, level: 99, xp: 17970837 },
slayer: { rank: 121165, level: 90, xp: 5748493 }, slayer: { rank: 265, level: 99, xp: 56230978 },
farming: { rank: 89460, level: 88, xp: 4624078 }, farming: { rank: 821, level: 99, xp: 62123353 },
runecraft: { rank: 53099, level: 80, xp: 2008229 }, runecraft: { rank: 169, level: 99, xp: 43127930 },
hunter: { rank: 169127, level: 73, xp: 1067670 }, hunter: { rank: 810, level: 99, xp: 37688883 },
construction: { rank: 115543, level: 82, xp: 2546048 }, construction: { rank: 92, level: 99, xp: 32005622 },
}, },
leaguePoints: { rank: -1, score: -1 }, leaguePoints: { rank: -1, score: -1 },
bountyHunter: { bountyHunter: {
rogue: { rank: -1, score: -1 }, rogue: { rank: -1, score: -1 },
hunter: { rank: -1, score: -1 }, hunter: { rank: -1, score: -1 },
}, },
lastManStanding: { rank: 32875, score: 500 }, lastManStanding: { rank: 4814, score: 898 },
clues: { clues: {
all: { rank: 24817, score: 476 }, all: { rank: 32, score: 12148 },
beginner: { rank: 212728, score: 1 }, beginner: { rank: 3105, score: 76 },
easy: { rank: 94827, score: 20 }, easy: { rank: 1997, score: 505 },
medium: { rank: 59099, score: 74 }, medium: { rank: 127, score: 4259 },
hard: { rank: 24642, score: 231 }, hard: { rank: 361, score: 915 },
elite: { rank: 5206, score: 99 }, elite: { rank: 392, score: 250 },
master: { rank: 6293, score: 51 }, master: { rank: 1, score: 6143 },
}, },
bosses: { bosses: {
abyssalSire: { rank: 374, score: 2780 }, abyssalSire: { rank: 382, score: 2780 },
alchemicalHydra: { rank: 934, score: 3000 }, alchemicalHydra: { rank: 944, score: 3000 },
barrows: { rank: 1936, score: 1452 }, barrows: { rank: 1981, score: 1452 },
bryophyta: { rank: 4919, score: 23 }, bryophyta: { rank: 4981, score: 23 },
callisto: { rank: -1, score: -1 }, callisto: { rank: 888, score: 1046 },
cerberus: { rank: -1, score: -1 }, cerberus: { rank: 613, score: 4856 },
chambersOfXeric: { rank: 101, score: 4038 }, chambersOfXeric: { rank: 102, score: 4038 },
chambersOfXericChallengeMode: { rank: 152, score: 334 }, chambersOfXericChallengeMode: { rank: 156, score: 334 },
chaosElemental: { rank: 6153, score: 133 }, chaosElemental: { rank: 6240, score: 133 },
chaosFanatic: { rank: 4501, score: 250 }, chaosFanatic: { rank: 4569, score: 250 },
commanderZilyana: { rank: 6806, score: 603 }, commanderZilyana: { rank: 6893, score: 603 },
corporealBeast: { rank: 1, score: 17798 }, corporealBeast: { rank: 1, score: 17798 },
crazyArchaeologist: { rank: 9160, score: 125 }, crazyArchaeologist: { rank: 9320, score: 125 },
dagannothPrime: { rank: 1021, score: 2802 }, dagannothPrime: { rank: 1030, score: 2802 },
dagannothRex: { rank: 4295, score: 1655 }, dagannothRex: { rank: 4342, score: 1655 },
dagannothSupreme: { rank: 959, score: 2951 }, dagannothSupreme: { rank: 966, score: 2951 },
derangedArchaeologist: { rank: 10009, score: 1 }, derangedArchaeologist: { rank: 10151, score: 1 },
generalGraardor: { rank: 1271, score: 2407 }, generalGraardor: { rank: 1288, score: 2407 },
giantMole: { rank: 378, score: 4669 }, giantMole: { rank: 377, score: 4669 },
grotesqueGuardians: { rank: 543, score: 1567 }, grotesqueGuardians: { rank: 545, score: 1567 },
hespori: { rank: 6003, score: 94 }, hespori: { rank: 6083, score: 94 },
kalphiteQueen: { rank: 263, score: 2897 }, kalphiteQueen: { rank: 264, score: 2897 },
kingBlackDragon: { rank: 4000, score: 1277 }, kingBlackDragon: { rank: 4052, score: 1277 },
kraken: { rank: 41016, score: 1477 }, kraken: { rank: 41643, score: 1477 },
kreeArra: { rank: 617, score: 2391 }, kreeArra: { rank: 625, score: 2391 },
krilTsutsaroth: { rank: 120, score: 2981 }, krilTsutsaroth: { rank: 120, score: 2981 },
mimic: { rank: 1, score: 109 }, mimic: { rank: 1, score: 109 },
nightmare: { rank: 3, score: 22666 },
obor: { rank: 26, score: 323 }, obor: { rank: 26, score: 323 },
sarachnis: { rank: 198, score: 1101 }, sarachnis: { rank: 201, score: 1101 },
scorpia: { rank: 81, score: 3404 }, scorpia: { rank: 82, score: 3404 },
skotizo: { rank: 5027, score: 61 }, skotizo: { rank: 5085, score: 61 },
gauntlet: { rank: 63, score: 375 }, gauntlet: { rank: 63, score: 375 },
corruptedGauntlet: { rank: 2845, score: 6 }, corruptedGauntlet: { rank: 2870, score: 6 },
theatreOfBlood: { rank: 6913, score: 138 }, theatreOfBlood: { rank: 6984, score: 138 },
thermonuclearSmokeDevil: { rank: 3999, score: 2000 }, thermonuclearSmokeDevil: { rank: 4043, score: 2000 },
tzKalZuk: { rank: 484, score: 8 }, tzKalZuk: { rank: 489, score: 8 },
tzTokJad: { rank: 957, score: 47 }, tzTokJad: { rank: 967, score: 47 },
venenatis: { rank: 10987, score: 223 }, venenatis: { rank: 11155, score: 223 },
vetion: { rank: 1923, score: 272 }, vetion: { rank: 1940, score: 272 },
vorkath: { rank: 8484, score: 1340 }, vorkath: { rank: 8623, score: 1340 },
wintertodt: { rank: 599, score: 1694 }, wintertodt: { rank: 605, score: 1694 },
zalcano: { rank: 12489, score: 435 }, zalcano: { rank: -1, score: -1 },
zulrah: { rank: 3810, score: 4583 }, zulrah: { rank: 3867, score: 4583 },
}, },
}; };

View File

@@ -3,5 +3,6 @@
"^.+\\.(t|j)sx?$": "ts-jest" "^.+\\.(t|j)sx?$": "ts-jest"
}, },
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
"moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"] "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"],
"testEnvironment": "node"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "osrs-json-hiscores", "name": "osrs-json-hiscores",
"version": "2.0.1", "version": "2.2.0",
"description": "The Oldschool Runescape API wrapper that does more!", "description": "The Oldschool Runescape API wrapper that does more!",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@@ -37,11 +37,11 @@
"homepage": "https://github.com/maxswa/osrs-json-hiscores#readme", "homepage": "https://github.com/maxswa/osrs-json-hiscores#readme",
"dependencies": { "dependencies": {
"axios": "^0.19.0", "axios": "^0.19.0",
"cheerio": "^1.0.0-rc.3" "jsdom": "^16.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/cheerio": "^0.22.11",
"@types/jest": "^24.0.14", "@types/jest": "^24.0.14",
"@types/jsdom": "^16.2.3",
"jest": "^24.8.0", "jest": "^24.8.0",
"np": "^5.0.3", "np": "^5.0.3",
"prettier": "^1.19.1", "prettier": "^1.19.1",

View File

@@ -1,5 +1,4 @@
import axios from 'axios'; import axios from 'axios';
import * as cheerio from 'cheerio';
import { import {
Player, Player,
Activity, Activity,
@@ -14,7 +13,6 @@ import {
ActivityName, ActivityName,
PlayerActivityRow, PlayerActivityRow,
Bosses, Bosses,
Boss,
} from './types'; } from './types';
import { import {
getStatsURL, getStatsURL,
@@ -30,6 +28,7 @@ import {
getActivityPageURL, getActivityPageURL,
BOSSES, BOSSES,
} from './utils'; } from './utils';
import { JSDOM } from 'jsdom';
export async function getStats(rsn: string): Promise<Player> { export async function getStats(rsn: string): Promise<Player> {
if (typeof rsn !== 'string') { if (typeof rsn !== 'string') {
@@ -46,13 +45,13 @@ export async function getStats(rsn: string): Promise<Player> {
axios(getStatsURL('ironman', rsn)).catch(err => err), axios(getStatsURL('ironman', rsn)).catch(err => err),
axios(getStatsURL('hardcore', rsn)).catch(err => err), axios(getStatsURL('hardcore', rsn)).catch(err => err),
axios(getStatsURL('ultimate', rsn)).catch(err => err), axios(getStatsURL('ultimate', rsn)).catch(err => err),
getRSNFormat(rsn), getRSNFormat(rsn).catch(() => undefined),
]); ]);
const [ironRes, hcRes, ultRes, formattedName] = otherResponses; const [ironRes, hcRes, ultRes, formattedName] = otherResponses;
const player: Player = { const player: Player = {
name: formattedName, name: formattedName || rsn,
mode: 'main', mode: 'main',
dead: false, dead: false,
deulted: false, deulted: false,
@@ -145,22 +144,26 @@ export async function getSkillPage(
const url = getSkillPageURL(mode, skill, page); const url = getSkillPageURL(mode, skill, page);
const response = await axios(url); const response = await axios(url);
const $ = cheerio.load(response.data); const dom = new JSDOM(response.data);
const playersHTML = $('.personal-hiscores__row').toArray(); const playersHTML = dom.window.document.querySelectorAll(
'.personal-hiscores__row'
);
const players: PlayerSkillRow[] = playersHTML.map(row => { const players: PlayerSkillRow[] = [];
const cells = row.children.filter(el => el.name === 'td'); playersHTML.forEach(row => {
const [rankEl, nameCell, levelEl, xpEl] = cells; const rankEl = row.querySelector('td');
const nameEl = nameCell.children.find(el => el.name === 'a'); const nameEl = row.querySelector('td a');
const isDead = !!nameCell.children.find(el => el.name === 'img'); const levelEl = row.querySelector('td.left + td');
const xpEl = row.querySelector('td.left + td + td');
const isDead = !!row.querySelector('td img');
return { players.push({
name: rsnFromElement(nameEl), name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl), rank: numberFromElement(rankEl),
level: numberFromElement(levelEl), level: numberFromElement(levelEl),
xp: numberFromElement(xpEl), xp: numberFromElement(xpEl),
dead: isDead, dead: isDead,
}; });
}); });
return players; return players;
@@ -181,21 +184,24 @@ export async function getActivityPage(
const url = getActivityPageURL(mode, activity, page); const url = getActivityPageURL(mode, activity, page);
const response = await axios(url); const response = await axios(url);
const $ = cheerio.load(response.data); const dom = new JSDOM(response.data);
const playersHTML = $('.personal-hiscores__row').toArray(); const playersHTML = dom.window.document.querySelectorAll(
'.personal-hiscores__row'
);
const players: PlayerActivityRow[] = playersHTML.map(row => { const players: PlayerActivityRow[] = [];
const cells = row.children.filter(el => el.name === 'td'); playersHTML.forEach(row => {
const [rankEl, nameCell, scoreEl] = cells; const rankEl = row.querySelector('td');
const nameEl = nameCell.children.find(el => el.name === 'a'); const nameEl = row.querySelector('td a');
const isDead = !!nameCell.children.find(el => el.name === 'img'); const scoreEl = row.querySelector('td.left + td');
const isDead = !!row.querySelector('td img');
return { players.push({
name: rsnFromElement(nameEl), name: rsnFromElement(nameEl),
rank: numberFromElement(rankEl), rank: numberFromElement(rankEl),
score: numberFromElement(scoreEl), score: numberFromElement(scoreEl),
dead: isDead, dead: isDead,
}; });
}); });
return players; return players;
@@ -213,10 +219,13 @@ export async function getRSNFormat(rsn: string): Promise<string> {
const url = getPlayerTableURL('main', rsn); const url = getPlayerTableURL('main', rsn);
try { try {
const response = await axios(url); const response = await axios(url);
const $ = cheerio.load(response.data); const dom = new JSDOM(response.data);
const rawName = $('[style="color:#AA0022;"]')[1].children[0].data; const spans = dom.window.document.querySelectorAll(
if (rawName) { 'span[style="color:#AA0022;"]'
return rawName.replace(/\uFFFD/g, ' '); );
if (spans.length >= 2) {
const nameSpan = spans[1];
return rsnFromElement(nameSpan);
} }
throw Error('Player not found'); throw Error('Player not found');
} catch { } catch {
@@ -277,27 +286,9 @@ export function parseStats(csv: string): Stats {
return newClues; return newClues;
}, {} as Clues); }, {} as Clues);
// TODO Remove as soon as Jagex's API is fixed
const brokenBosses: Boss[] = ['callisto', 'cerberus'];
const TEMPBOSSES: Boss[] = BOSSES.reduce<Boss[]>(
(prev, curr) => (brokenBosses.includes(curr) ? prev : [...prev, curr]),
[]
);
const bosses: Bosses = bossObjects.reduce<Bosses>((prev, curr, index) => { const bosses: Bosses = bossObjects.reduce<Bosses>((prev, curr, index) => {
const newBosses = { ...prev }; const newBosses = { ...prev };
newBosses[BOSSES[index]] = curr;
// TODO Remove as soon as Jagex's API is fixed
if (BOSSES[index] === brokenBosses[0]) {
brokenBosses.forEach(broken => {
newBosses[broken] = {
rank: -1,
score: -1,
};
});
}
newBosses[TEMPBOSSES[index]] = curr;
return newBosses; return newBosses;
}, {} as Bosses); }, {} as Bosses);

View File

@@ -89,6 +89,7 @@ export type Boss =
| 'kreeArra' | 'kreeArra'
| 'krilTsutsaroth' | 'krilTsutsaroth'
| 'mimic' | 'mimic'
| 'nightmare'
| 'obor' | 'obor'
| 'sarachnis' | 'sarachnis'
| 'scorpia' | 'scorpia'

View File

@@ -7,7 +7,7 @@ import {
ActivityName, ActivityName,
} from '../types'; } from '../types';
export const BASE_URL = 'http://services.runescape.com/m=hiscore_oldschool'; export const BASE_URL = 'https://secure.runescape.com/m=hiscore_oldschool';
export const STATS_URL = 'index_lite.ws?player='; export const STATS_URL = 'index_lite.ws?player=';
export const SCORES_URL = 'overall.ws?'; export const SCORES_URL = 'overall.ws?';
@@ -97,6 +97,7 @@ export const BOSSES: Boss[] = [
'kreeArra', 'kreeArra',
'krilTsutsaroth', 'krilTsutsaroth',
'mimic', 'mimic',
'nightmare',
'obor', 'obor',
'sarachnis', 'sarachnis',
'scorpia', 'scorpia',
@@ -161,6 +162,7 @@ export const FORMATTED_BOSS_NAMES: FormattedBossNames = {
kreeArra: "Kree'Arra", kreeArra: "Kree'Arra",
krilTsutsaroth: "K'ril Tsutsaroth", krilTsutsaroth: "K'ril Tsutsaroth",
mimic: 'Mimic', mimic: 'Mimic',
nightmare: 'The Nightmare of Ashihama',
obor: 'Obor', obor: 'Obor',
sarachnis: 'Sarachnis', sarachnis: 'Sarachnis',
scorpia: 'Scorpia', scorpia: 'Scorpia',

View File

@@ -35,13 +35,13 @@ export const getActivityPageURL = (
activity activity
)}&page=${page}`; )}&page=${page}`;
export const numberFromElement = (el: CheerioElement) => { export const numberFromElement = (el: Element | null) => {
const innerText = el.firstChild.data; const { innerHTML } = el || {};
const number = innerText ? innerText.replace(/[\n|,]/g, '') : '-1'; const number = innerHTML?.replace(/[\n|,]/g, '') ?? '-1';
return parseInt(number, 10); return parseInt(number, 10);
}; };
export const rsnFromElement = (el: CheerioElement | undefined) => { export const rsnFromElement = (el: Element | null) => {
const innerText = el?.firstChild.data; const { innerHTML } = el || {};
return innerText ? innerText.replace(/\uFFFD/g, ' ') : ''; return innerHTML?.replace(/\uFFFD/g, ' ') || '';
}; };

1324
yarn.lock

File diff suppressed because it is too large Load Diff