'use strict' export default class { constructor(str) { // select all lines containing card serial numbers let cardLinesRE = /^.*\b\d-\d{3}[A-Z]?\b.*$/gm let cardLines = str.match(cardLinesRE) let cardCounts = {} cardLines.forEach(cardLine => { // extract serial (guaranteed to be in here!) let serialRE = /\b(\d-\d{3})[A-Z]?\b/i let serial = serialRE.exec(cardLine)[1] // strip out serial number cardLine = cardLine.replace(serialRE, '') let countREs = [ // prioritize a count with "times" symbol *, x, × /\b([0-9]+)(?:[*×]|[x]\b)/, /(?:[*×]|\b[x])([0-9]+)\b/, // next priority: count with whitespace /\s+([0-9]+)\s+/, /\s+([0-9]+)\b/, /\b([0-9]+)\s+/, // least priority: any simple number /\b([0-9]+)\b/ ] // fallback value let count = 1 for (let i = 0; i < countREs.length; i++) { let data = countREs[i].exec(cardLine) if (data) { count = Number(data[1]) break } } // count copies if (!cardCounts[serial]) { cardCounts[serial] = 0 } cardCounts[serial] += count }) // push card data into deck this.cards = [] Object.keys(cardCounts).forEach(serial => { this.cards.push({ serial: serial, count: cardCounts[serial] }) }) // strip out lines with serial numbers str = str.replace(cardLinesRE, '') // then strip out anything after the first empty line str = str.replace(/^[\s]*$[^]*/m, '') // select the line containing 'deck name:' // and its successor (ffdecks format) let metaRE = /^Deck Name: (.+)$[\s]*?^(.+)$/m let metaData = metaRE.exec(str) // fallback this.name = 'Unnamed Deck' this.note = '' if (!metaData) { // use lax format: :[deck name][newline][note] metaRE = /[^]*?:(.+)$[\s]*?^([^]*)/m metaData = metaRE.exec(str) } // look again, I am not an else! if (metaData) { // extract matches this.name = metaData[1].trim() this.note = metaData[2].trim() } } count() { return this.cards.reduce((total, card) => total + card.count, 0) } plainObject() { return { name: this.name, note: this.note, cards: this.cards } } }