mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2025-12-14 20:15:51 +00:00
refactor: remove exceptions from parser
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { Result, ok, err } from 'neverthrow'
|
||||
import {
|
||||
CLIENT_STRINGS as _$,
|
||||
CLIENT_STRINGS_REF as _$REF,
|
||||
@@ -20,9 +21,9 @@ type SectionParseResult =
|
||||
| 'PARSER_SKIPPED'
|
||||
|
||||
type ParserFn = (section: string[], item: ParserState) => SectionParseResult
|
||||
type VirtualParserFn = (item: ParserState) => void
|
||||
type VirtualParserFn = (item: ParserState) => Result<never, string> | void
|
||||
|
||||
export interface ParserState extends ParsedItem {
|
||||
interface ParserState extends ParsedItem {
|
||||
name: string
|
||||
baseType: string | undefined
|
||||
infoVariants: BaseType[]
|
||||
@@ -70,11 +71,51 @@ const parsers: Array<ParserFn | { virtual: VirtualParserFn }> = [
|
||||
{ virtual: calcBasePercentile }
|
||||
]
|
||||
|
||||
export function parseClipboard (clipboard: string) {
|
||||
const lines = clipboard.split(/\r?\n/)
|
||||
export function parseClipboard (clipboard: string): Result<ParsedItem, string> {
|
||||
try {
|
||||
let sections = itemTextToSections(clipboard)
|
||||
|
||||
if (sections[0][2] === _$.CANNOT_USE_ITEM) {
|
||||
sections[0].pop() // remove CANNOT_USE_ITEM line
|
||||
sections[1].unshift(...sections[0]) // prepend item class & rarity into second section
|
||||
sections.shift() // remove first section where CANNOT_USE_ITEM line was
|
||||
}
|
||||
const parsed = parseNamePlate(sections[0])
|
||||
if (!parsed.isOk()) return parsed
|
||||
|
||||
sections.shift()
|
||||
parsed.value.rawText = clipboard
|
||||
|
||||
// each section can be parsed at most by one parser
|
||||
for (const parser of parsers) {
|
||||
if (typeof parser === 'object') {
|
||||
const error = parser.virtual(parsed.value)
|
||||
if (error) return error
|
||||
continue
|
||||
}
|
||||
|
||||
for (const section of sections) {
|
||||
const result = parser(section, parsed.value)
|
||||
if (result === 'SECTION_PARSED') {
|
||||
sections = sections.filter(s => s !== section)
|
||||
break
|
||||
} else if (result === 'PARSER_SKIPPED') {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Object.freeze(parsed)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
return err('item.parse_error')
|
||||
}
|
||||
}
|
||||
|
||||
function itemTextToSections (text: string) {
|
||||
const lines = text.split(/\r?\n/)
|
||||
lines.pop()
|
||||
|
||||
let sections: string[][] = [[]]
|
||||
const sections: string[][] = [[]]
|
||||
lines.reduce((section, line) => {
|
||||
if (line !== '--------') {
|
||||
section.push(line)
|
||||
@@ -85,40 +126,7 @@ export function parseClipboard (clipboard: string) {
|
||||
return section
|
||||
}
|
||||
}, sections[0])
|
||||
sections = sections.filter(section => section.length)
|
||||
|
||||
if (sections[0][2] === _$.CANNOT_USE_ITEM) {
|
||||
sections[0].pop() // remove CANNOT_USE_ITEM line
|
||||
sections[1].unshift(...sections[0]) // prepend item class & rarity into second section
|
||||
sections.shift() // remove first section where CANNOT_USE_ITEM line was
|
||||
}
|
||||
const parsed = parseNamePlate(sections[0])
|
||||
if (!parsed) {
|
||||
return null
|
||||
}
|
||||
|
||||
sections.shift()
|
||||
parsed.rawText = clipboard
|
||||
|
||||
// each section can be parsed at most by one parser
|
||||
for (const parser of parsers) {
|
||||
if (typeof parser === 'object') {
|
||||
parser.virtual(parsed)
|
||||
continue
|
||||
}
|
||||
|
||||
for (const section of sections) {
|
||||
const result = parser(section, parsed)
|
||||
if (result === 'SECTION_PARSED') {
|
||||
sections = sections.filter(s => s !== section)
|
||||
break
|
||||
} else if (result === 'PARSER_SKIPPED') {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Object.freeze(parsed)
|
||||
return sections.filter(section => section.length)
|
||||
}
|
||||
|
||||
function normalizeName (item: ParserState) {
|
||||
@@ -180,7 +188,7 @@ function findInDatabase (item: ParserState) {
|
||||
info = ITEM_BY_REF('ITEM', item.baseType ?? item.name)
|
||||
}
|
||||
if (!info?.length) {
|
||||
throw new Error('UNKNOWN_ITEM')
|
||||
return err('item.unknown')
|
||||
}
|
||||
if (info[0].unique) {
|
||||
info = info.filter(info => info.unique!.base === item.baseType)
|
||||
@@ -267,7 +275,7 @@ function parseNamePlate (section: string[]) {
|
||||
if (section.length < 3 ||
|
||||
!section[0].startsWith(_$.ITEM_CLASS) ||
|
||||
!section[1].startsWith(_$.RARITY)) {
|
||||
return null
|
||||
return err('item.parse_error')
|
||||
}
|
||||
|
||||
const item: ParserState = {
|
||||
@@ -311,10 +319,10 @@ function parseNamePlate (section: string[]) {
|
||||
item.rarity = ItemRarity.Unique
|
||||
break
|
||||
default:
|
||||
return null
|
||||
return err('item.unknown')
|
||||
}
|
||||
|
||||
return item
|
||||
return ok(item)
|
||||
}
|
||||
|
||||
function parseInfluence (section: string[], item: ParsedItem) {
|
||||
|
||||
Reference in New Issue
Block a user