parser-de-notas-de-corretagem 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notes-parser.js","mappings":"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","sources":["webpack://parser-de-notas-de-corretagem/./src/asset-crawler.ts","webpack://parser-de-notas-de-corretagem/./src/notes-parser.ts","webpack://parser-de-notas-de-corretagem/external commonjs \"axios\"","webpack://parser-de-notas-de-corretagem/external commonjs \"pdfjs-dist\"","webpack://parser-de-notas-de-corretagem/external node-commonjs \"fs\"","webpack://parser-de-notas-de-corretagem/external node-commonjs \"https\"","webpack://parser-de-notas-de-corretagem/external node-commonjs \"path\"","webpack://parser-de-notas-de-corretagem/webpack/bootstrap","webpack://parser-de-notas-de-corretagem/webpack/startup"],"sourcesContent":["import axios from \"axios\";\r\nimport https from 'https';\r\nimport assets from '../assets.json';\r\nconst httpsAgent = new https.Agent({ rejectUnauthorized: false });\r\n\r\n/**\r\n * B3 request object constructor\r\n */\r\nclass ListedStocksRequest {\r\n language: string = 'pt-br';\r\n pageNumber: number;\r\n pageSize: 20|40|60|120 = 120;\r\n \r\n constructor(pageNumber: number) {\r\n this.pageNumber = pageNumber;\r\n this.pageSize = 120;\r\n }\r\n\r\n}\r\n\r\n/**\r\n * Infos about the stock\r\n */\r\ninterface StockInfos {\r\n /**\r\n * CVM code\r\n */\r\n codeCVM: string;\r\n /**\r\n * Issuing Company (B3 Code)\r\n */\r\n issuingCompany: string;\r\n /**\r\n * Company name\r\n */\r\n companyName: string;\r\n /**\r\n * Trading name (same name as in the brokerage note)\r\n */\r\n tradingName: string;\r\n /**\r\n * Company's CNPJ\r\n */\r\n cnpj: string;\r\n marketIndicator: string;\r\n typeBDR: string;\r\n dateListing: string;\r\n status: string;\r\n segment: string;\r\n segmentEng: string;\r\n type: string;\r\n market: string;\r\n}\r\n\r\n/**\r\n * Infos about the page and the total amount of records\r\n */\r\ninterface PageInfo {\r\n /**\r\n * Current page number\r\n */\r\n pageNumber: number;\r\n /**\r\n * Number of results in the page (can be less if it's the last page)\r\n */\r\n pageSize: number;\r\n /**\r\n * Number of total records\r\n */\r\n totalRecords: number;\r\n /**\r\n * Number of total pages\r\n */\r\n totalPages: number;\r\n}\r\n\r\n/**\r\n * Crawler result\r\n */\r\ninterface CrawlerRequestResult {\r\n \"page\": PageInfo;\r\n \"results\": StockInfos[];\r\n}\r\n\r\n/**\r\n * Assets main infos\r\n */\r\nexport interface Asset {\r\n /**\r\n * Asset's code\r\n */\r\n code: string;\r\n /**\r\n * Asset's name\r\n */\r\n name: string;\r\n /**\r\n * Asset's cnpj\r\n */\r\n cnpj?: string;\r\n}\r\n\r\n/**\r\n * Assets crawler manager\r\n */\r\nexport class AssetCrawler {\r\n\r\n /**\r\n * Assets cached\r\n */\r\n protected assets: StockInfos[];\r\n /**\r\n * Assets defined on runtime\r\n */\r\n customAssets: Asset[] = [];\r\n /**\r\n * Auto-update flag\r\n */\r\n autoUpdate: boolean = false;\r\n /**\r\n * Auto-update timeout\r\n */\r\n private updaterTimeout = 7*24*3600*1000;\r\n /**\r\n * Auto-update timeout when any failure happens\r\n */\r\n private updaterTimeoutIfFailed = 24*3600*1000;\r\n\r\n /**\r\n * Crawler URLs\r\n */\r\n private urls = {\r\n listedStocks: Buffer.from('aHR0cHM6Ly9zaXN0ZW1hc3dlYmIzLWxpc3RhZG9zLmIzLmNvbS5ici9saXN0ZWRDb21wYW5pZXNQcm94eS9Db21wYW55Q2FsbC9HZXRJbml0aWFsQ29tcGFuaWVz', 'base64').toString('utf-8')\r\n }\r\n\r\n /**\r\n * Instantiate a new `AssetCrawler`\r\n * @param autoUpdate whether the application should auto-update\r\n * the list of assets for new changes. Default is `false`. Require internet connection\r\n */\r\n constructor(autoUpdate?: boolean) {\r\n this.assets = assets;\r\n this.autoUpdate = autoUpdate || false;\r\n if (this.autoUpdate) {\r\n this.updater(0);\r\n }\r\n }\r\n\r\n /**\r\n * Update the listed assets after a timeout\r\n * @param timeout update after `timeout` milliseconds\r\n */\r\n updater(timeout: number = this.updaterTimeout) {\r\n setTimeout(() => {\r\n this.getListedAssets()\r\n .catch(err => {\r\n console.log(`Error getting listed assets. Trying again in 1 day`);\r\n if (err instanceof Error) console.log(err.message);\r\n this.updater(this.updaterTimeoutIfFailed);\r\n })\r\n .then(() => {\r\n this.updater();\r\n })\r\n }, timeout);\r\n }\r\n\r\n /**\r\n * Generate a URL page to get the information from. Input is the page number.\r\n * @param page page number\r\n * @returns the URL to retrieve the information\r\n */\r\n private getUrlByPage(page: number): string {\r\n return `${this.urls.listedStocks}/${Buffer.from(JSON.stringify(new ListedStocksRequest(page))).toString('base64')}`\r\n }\r\n\r\n /**\r\n * Update the current listed assets\r\n */\r\n async getListedAssets(): Promise<void> {\r\n const firstResult = await axios.get(this.getUrlByPage(1), { httpsAgent });\r\n if (!('data' in firstResult)) throw new Error(`Unexpected response: ${firstResult}`);\r\n\r\n let data: CrawlerRequestResult = firstResult.data;\r\n let results: StockInfos[] = data.results;\r\n \r\n while(data.page.totalPages > data.page.pageNumber) {\r\n const getResult = await axios.get(this.getUrlByPage(data.page.pageNumber + 1), { httpsAgent });\r\n if (!('data' in getResult)) throw new Error(`Unexpected response: ${getResult}`);\r\n data = getResult.data;\r\n data.page = data.page;\r\n results.push(...data.results);\r\n }\r\n \r\n this.assets = results;\r\n\r\n }\r\n\r\n /**\r\n * Parse the stock name and returns the stock code\r\n * @param name title of the stock in the brokerage note\r\n * @returns the stock code\r\n */\r\n getCodeFromTitle(name: string): Asset {\r\n // If the stock was manually set\r\n let customDefined: Asset | undefined = this.customAssets.find(c => name.includes(c.name));\r\n if (customDefined) return customDefined\r\n\r\n // If it's a FII, the code is in the name\r\n let match = name.match(/FII\\s.*?\\s([^\\s]+?)\\sCI/i);\r\n if (match && match[1]) return {code: match[1], name};\r\n\r\n // Else, parse it\r\n let type: '3'|'4'|'11' = '3';\r\n let indexOf: number;\r\n if (name.indexOf(' ON') !== -1) { indexOf = name.indexOf(' ON'); type = '3'}\r\n else if (name.indexOf(' PN') !== -1) { indexOf = name.indexOf(' PN'); type = '4'}\r\n else if (name.indexOf(' UNT') !== -1) { indexOf = name.indexOf(' UNT'); type = '11'}\r\n else indexOf = name.length;\r\n let justTheName = name.slice(0, indexOf);\r\n const stock = this.assets.find(el => el.tradingName === justTheName);\r\n if (!stock) throw new Error(`No stock found for ${name}`);\r\n\r\n return {code: stock.issuingCompany + type, name, cnpj: stock.cnpj};\r\n\r\n }\r\n\r\n}\r\n","import fs from 'fs';\r\nimport path from \"path\";\r\nimport { getDocument as openPDF, PDFDocumentProxy as PDFDocument } from 'pdfjs-dist';\r\nimport { Asset, AssetCrawler } from \"./asset-crawler\";\r\n\r\n/**\r\n * Deal made in a `NegotiationNote` type\r\n */\r\nexport interface Deal {\r\n /**\r\n * Deal type\r\n */\r\n type: 'buy' | 'sell'\r\n /**\r\n * Stock/FII code\r\n */\r\n code: string\r\n /**\r\n * Amount bought/sold\r\n */\r\n quantity: number\r\n /**\r\n * Average value bought/sold with fees applied\r\n */\r\n average: string\r\n /**\r\n * Total amount bought/sold with fees applied\r\n */\r\n price: string\r\n /**\r\n * Deal date in format yyyy-MM-dd\r\n */\r\n date: string\r\n /**\r\n * Asset's CNPJ\r\n */\r\n cnpj: string\r\n}\r\n\r\n/**\r\n * A parsed Negotiation Note type\r\n */\r\nexport class NegotiationNote {\r\n /**\r\n * Negotiation note number\r\n */\r\n number: string = '';\r\n /**\r\n * The total amount bought with fees applied\r\n */\r\n buyTotal: string = '0'\r\n /**\r\n * The total amount sold with fees applied\r\n */\r\n sellTotal: string = '0'\r\n /**\r\n * The total amount of buy fees\r\n */\r\n buyFees: string = '0'\r\n /**\r\n * The total amount of sell fees\r\n */\r\n sellFees: string = '0'\r\n /**\r\n * The total amount of fees\r\n */\r\n fees: string = '0'\r\n /**\r\n * Negotiation note date in format yyyy-MM-dd\r\n */\r\n date: string = ''\r\n /**\r\n * Negotiation note holder\r\n */\r\n holder: string = ''\r\n /**\r\n * Array of deals with buys and sells\r\n */\r\n deals: Deal[] = []\r\n}\r\n\r\n/**\r\n * Brokerage notes parser\r\n */\r\nexport class NoteParser {\r\n\r\n /**\r\n * Path to the JSON data file\r\n */\r\n private stockParser: AssetCrawler;\r\n\r\n /**\r\n * Instantiate a new `NoteParser`\r\n * @param autoUpdateLookUpList whether the application should auto-update\r\n * the list of assets for new changes every week. Default is `false`. Require internet connection.\r\n * Updating this package to the latest version also gets the latest infos\r\n */\r\n constructor(autoUpdateLookUpList?: boolean) {\r\n this.stockParser = new AssetCrawler(autoUpdateLookUpList);\r\n\r\n // Some manually defined stocks\r\n this.defineStock('TIET11', 'AES TIETE E UNT');\r\n this.defineStock('AESB3', 'AES TIETE E ON');\r\n this.defineStock('AESB4', 'AES TIETE E PN');\r\n this.defineStock('CSAN11', 'COSAN LOG UNT');\r\n this.defineStock('CSAN3', 'COSAN LOG ON');\r\n this.defineStock('CSAN4', 'COSAN LOG PN');\r\n this.defineStock('MDIA11', 'M.DIASBRANCO UNT');\r\n this.defineStock('MDIA3', 'M.DIASBRANCO ON');\r\n this.defineStock('MDIA4', 'M.DIASBRANCO PN');\r\n this.defineStock('BIDI3', 'BANCO INTER ON');\r\n this.defineStock('BIDI11', 'BANCO INTER UNT');\r\n }\r\n\r\n /**\r\n * Read and parse a given PDF negotiation note by its full path\r\n * @param noteFullPath the full path to the PDF note to be parsed\r\n * @returns an `Array` of `NegotiationNote`\r\n */\r\n async parseNote(noteFullPath: string, possiblePasswords?: string[]): Promise<NegotiationNote[]> {\r\n\r\n // Check PDF path\r\n if (!fs.existsSync(noteFullPath)) throw new Error(`Couldn't find the file ${noteFullPath}`);\r\n \r\n // Try to open the PDF using the provided passwords, if any\r\n let parseResults: NegotiationNote[] = []\r\n const noteName: string = path.basename(noteFullPath);\r\n let invalidPassword: boolean = false;\r\n let pdf: PDFDocument | undefined;\r\n if (!possiblePasswords || !possiblePasswords.length) {\r\n pdf = await openPDF({url: noteFullPath}).promise;\r\n } else {\r\n for await (const pass of possiblePasswords) {\r\n try {\r\n pdf = await openPDF({url: noteFullPath, password: pass}).promise;\r\n break;\r\n } catch (error: any) {\r\n /** Prevent the failure and try again with another password */\r\n if (error instanceof Error) {\r\n if (!error.message.includes('No password given') && !error.message.includes('Incorrect Password')) throw error;\r\n else invalidPassword = true;\r\n } else if (typeof error === 'string') {\r\n if (!error.includes('No password given') && !error.includes('Incorrect Password')) throw error;\r\n else invalidPassword = true;\r\n }\r\n else throw error;\r\n }\r\n }\r\n }\r\n\r\n // Check if the open result\r\n if (!pdf && invalidPassword) throw new Error(`None of the provided passwords could open the note ${noteFullPath}`);\r\n else if (!pdf) throw new Error(`Can't open note ${noteFullPath}. The document returned no content`);\r\n\r\n // Parse the PDF content\r\n try {\r\n // Patterns\r\n let holderPattern: RegExp = /data.*\\s+\\d{2}\\/\\d{2}\\/\\d{4}\\s+(\\w+)/i;\r\n let noteNumberPattern: RegExp = /Nr\\. nota\\s+(\\d+)/i;\r\n let datePattern: RegExp = /data.*\\s+(\\d{2}\\/\\d{2}\\/\\d{4})/i;\r\n let buysAndSellsPattern: RegExp = /\\d[\\d,.]*\\s+(\\d[\\d,.]*)\\s+(\\d[\\d,.]*)\\s+\\d[\\d,.]*\\s+\\d[\\d,.]*\\s+\\d[\\d,.]*\\s+\\d[\\d,.]*\\s+\\d[\\d,.]*\\s*Resumo dos Negócios/;\r\n let feesPattern: RegExp[] = [\r\n /(\\d[\\d,.]*)\\nTaxa de liquidação/,\r\n /(\\d[\\d,.]*)\\nTaxa de Registro/,\r\n /(\\d[\\d,.]*)\\nTaxa de termo\\/opções/,\r\n /(\\d[\\d,.]*)\\nTaxa A.N.A./,\r\n /(\\d[\\d,.]*)\\nEmolumentos/,\r\n /(\\d[\\d,.]*)\\nTaxa Operacional/,\r\n /(\\d[\\d,.]*)\\nExecução/,\r\n /(\\d[\\d,.]*)\\nTaxa de Custódia/,\r\n /(\\d[\\d,.]*)\\nImpostos/,\r\n /(\\d[\\d,.]*)\\nI\\.R\\.R\\.F\\. s\\/ operações, base/,\r\n /(\\d[\\d,.]*)\\nOutros/\r\n ];\r\n let stockPattern: RegExp = /1-BOVESPA\\s+(\\w)\\s+(\\w+)\\s+([\\t \\s+\\w\\/.]+)\\s+(?:#\\w*\\s+)?(\\d+)\\s+([\\w,]+)\\s+([\\w,.]+)\\s+/g;\r\n let match: RegExpMatchArray | null;\r\n\r\n // Iterate over the pages\r\n let pageContent: string = '';\r\n for await (const index of Array(pdf.numPages).keys()) {\r\n let i = index + 1;\r\n let page = await pdf.getPage(i);\r\n let data = await page.getTextContent();\r\n // Get page content\r\n for (let j = 0; j < data.items.length; j++) {\r\n const item = data.items[j];\r\n if ('str' in item) {\r\n pageContent += `${item.str}\\n`;\r\n }\r\n }\r\n if (pageContent.match(buysAndSellsPattern) && pageContent.match(noteNumberPattern)) {\r\n // fs.writeFileSync(path.join(__dirname, 'content.txt'), pageContent, {encoding: 'utf-8', flag: 'a+'});\r\n\r\n // Get note's number\r\n let noteNumber: string | undefined\r\n match = pageContent.match(noteNumberPattern);\r\n if (match && match[1]) noteNumber = match[1];\r\n else throw new Error(`No note number found for the negotiation note '${noteName}'`);\r\n let parseResult = parseResults.find(el => el.number === noteNumber);\r\n if (!parseResult) {\r\n parseResult = new NegotiationNote();\r\n parseResults.push(parseResult);\r\n }\r\n parseResult.number = noteNumber;\r\n\r\n // Get the holder\r\n let holder: string | undefined;\r\n match = pageContent.match(holderPattern);\r\n if (match && match[1]) holder = match[1][0].toUpperCase() + match[1].slice(1).toLowerCase();\r\n else throw new Error(`No holder found for the negotiation note '${noteName}'`);\r\n parseResult.holder = holder.toLocaleLowerCase();\r\n\r\n // Get the date\r\n let date: string | undefined;\r\n match = pageContent.match(datePattern);\r\n if (match && match[1]) date = formatDateToShow(match[1]);\r\n else throw new Error(`No date found for the negotiation note '${noteName}'`);\r\n parseResult.date = date;\r\n\r\n // Note total\r\n let buyTotal: number = 0;\r\n let sellTotal: number = 0;\r\n if ((match = pageContent.match(buysAndSellsPattern)) !== null) {\r\n sellTotal = parseFloat(match[1].replace(/\\./g, '').replace(',', '.'));\r\n buyTotal = parseFloat(match[2].replace(/\\./g, '').replace(',', '.'));\r\n } else {\r\n console.log(`Error parsing note '${noteName}'. Couldn't get note buys and sells values`);\r\n }\r\n\r\n // Get the fees\r\n let fees: number = 0;\r\n feesPattern.forEach(fee => {\r\n let match = pageContent.match(fee);\r\n if (match && match[1]) {\r\n fees += parseFloat(match[1].replace(/\\./g, '').replace(',', '.')); \r\n }\r\n });\r\n if (fees) {\r\n parseResult.fees = (parseFloat(parseResult.fees) + fees).toFixed(2);\r\n }\r\n\r\n // Generate the CheckOut for the value bought\r\n if (buyTotal) {\r\n parseResult.buyTotal = buyTotal.toFixed(2);\r\n } \r\n \r\n // Generate the CheckIn for the value sold\r\n if (sellTotal) {\r\n parseResult.sellTotal = sellTotal.toFixed(2);\r\n }\r\n\r\n while ((match = stockPattern.exec(pageContent)) != null) {\r\n let op: string = match[1];\r\n // let market: string = match[2];\r\n let stock: Asset = this.stockParser.getCodeFromTitle(match[3].replace(/\\s+/g, ' '));\r\n let quantity: number = parseInt(match[4]);\r\n // let each: number = parseFloat(match[5].replace('.', '').replace(',', '.'));\r\n let transactionValue: number = parseFloat(match[6].replace('.', '').replace(',', '.'));\r\n\r\n if (!stock) console.log(`Can't find ${match[3]}`);\r\n\r\n // if (market === 'FRACIONARIO') stock += 'F';\r\n \r\n // Set 'buy' or 'sell'\r\n if (op === 'C') {\r\n let deal = parseResult.deals.find(el => el.code === stock.code && el.type === 'buy');\r\n if (!deal) {\r\n deal = {\r\n type: 'buy',\r\n code: stock.code,\r\n quantity: quantity,\r\n average: '0',\r\n price: transactionValue.toFixed(2),\r\n date: parseResult.date,\r\n cnpj: stock.cnpj?stock.cnpj:''\r\n };\r\n parseResult.deals.push(deal);\r\n } else {\r\n deal.price = (parseFloat(deal.price) + transactionValue).toString();\r\n deal.quantity = deal.quantity + quantity;\r\n }\r\n } else {\r\n let deal = parseResult.deals.find(el => el.code === stock.code && el.type === 'sell');\r\n if (!deal) {\r\n deal = {\r\n type: 'sell',\r\n code: stock.code,\r\n quantity: quantity,\r\n average: '0',\r\n price: transactionValue.toFixed(2),\r\n date: parseResult.date,\r\n cnpj: stock.cnpj?stock.cnpj:''\r\n };\r\n parseResult.deals.push(deal);\r\n } else {\r\n deal.price = (parseFloat(deal.price) + transactionValue).toString();\r\n deal.quantity = deal.quantity - quantity\r\n }\r\n }\r\n\r\n }\r\n\r\n pageContent = '';\r\n }\r\n }\r\n\r\n } catch (error: any) {\r\n if (error instanceof Error) {\r\n console.log(error.message);\r\n console.log(error);\r\n } else {\r\n console.log(`An error occurred during the notes parse`);\r\n console.log(error);\r\n }\r\n }\r\n\r\n try {\r\n // Process the fees\r\n parseResults.forEach(note => {\r\n const fees: number = parseFloat(note.fees);\r\n if (fees) {\r\n const buyTotal: number = parseFloat(note.buyTotal);\r\n const sellTotal: number = parseFloat(note.sellTotal);\r\n const buyFees: number = fees*buyTotal/(buyTotal+sellTotal);\r\n const sellFees: number = fees*sellTotal/(buyTotal+sellTotal);\r\n note.deals.forEach(deal => {\r\n const price: number = parseFloat(deal.price);\r\n if (deal.type === 'buy') {\r\n deal.price = (Math.fround(10*(price + buyFees*price/buyTotal))/10).toFixed(2);\r\n } else {\r\n deal.price = (Math.fround(10*(price - sellFees*price/sellTotal))/10).toFixed(2);\r\n }\r\n deal.average = (parseFloat(deal.price)/Math.abs(deal.quantity)).toFixed(2);\r\n });\r\n note.buyFees = buyFees.toFixed(2);\r\n note.sellFees = sellFees.toFixed(2);\r\n note.buyTotal = (buyTotal + buyFees).toFixed(2);\r\n note.sellTotal = (sellTotal - sellFees).toFixed(2);\r\n }\r\n });\r\n } catch (error: any) {\r\n if (error instanceof Error) {\r\n console.log(error.message);\r\n console.log(error);\r\n } else {\r\n console.log(`An error occurred while processing the notes`);\r\n console.log(error);\r\n }\r\n }\r\n\r\n // Format the CNPJs\r\n parseResults.forEach(el => {\r\n el.deals.forEach(deal => {\r\n // For some reason, CNPJs starting wit zeros have them suppressed, even thought it's a string and not a number ¯\\_(ツ)_/¯\r\n if (deal.cnpj.length < 14) deal.cnpj = new Array(14 - deal.cnpj.length).fill('0').join('') + deal.cnpj;\r\n\r\n deal.cnpj = deal.cnpj.split('').map((c, index) => {\r\n if (index === 2 || index === 5) return '.' + c;\r\n else if (index === 8) return '/' + c;\r\n else if (index === 12) return '-' + c;\r\n else return c;\r\n }).join('');\r\n })\r\n });\r\n\r\n // console.log(noteResults);\r\n return parseResults;\r\n }\r\n\r\n /**\r\n * Add stock definition\r\n * @param code stock code\r\n * @param name stock name\r\n * @param cnpj stock CNPJ\r\n */\r\n defineStock(code: string, name: string, cnpj?: string): void {\r\n // Skip duplicates\r\n if (!this.stockParser.customAssets.find(a => a.code === code)) {\r\n this.stockParser.customAssets.push({code, name, cnpj});\r\n };\r\n }\r\n\r\n}\r\n\r\n/**\r\n * Convert a date to be displayed by local\r\n * @param date the date formatted as yyyy-MM-dd\r\n * @returns the formatted date\r\n */\r\nfunction formatDateToShow (date: string | Date) {\r\n if (typeof date === 'string') {\r\n if (!date.match(/\\d{4}-\\d{2}-\\d{2}/)) {\r\n return date;\r\n } else {\r\n return date.split('-').reverse().join('/');\r\n }\r\n } else {\r\n return '';\r\n }\r\n}","module.exports = require(\"axios\");","module.exports = require(\"pdfjs-dist\");","module.exports = require(\"fs\");","module.exports = require(\"https\");","module.exports = require(\"path\");","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(824);\n"],"names":["httpsAgent","Agent","rejectUnauthorized","ListedStocksRequest","constructor","pageNumber","language","pageSize","this","autoUpdate","customAssets","updaterTimeout","updaterTimeoutIfFailed","urls","listedStocks","Buffer","from","toString","assets","updater","timeout","setTimeout","getListedAssets","catch","err","console","log","Error","message","then","getUrlByPage","page","JSON","stringify","firstResult","get","data","results","totalPages","getResult","push","getCodeFromTitle","name","customDefined","find","c","includes","match","code","indexOf","type","length","justTheName","slice","stock","el","tradingName","issuingCompany","cnpj","NegotiationNote","number","buyTotal","sellTotal","buyFees","sellFees","fees","date","holder","deals","formatDateToShow","split","reverse","join","autoUpdateLookUpList","stockParser","AssetCrawler","defineStock","parseNote","noteFullPath","possiblePasswords","existsSync","parseResults","noteName","basename","pdf","invalidPassword","pass","url","password","promise","error","holderPattern","noteNumberPattern","datePattern","buysAndSellsPattern","feesPattern","stockPattern","pageContent","Array","numPages","keys","i","getPage","getTextContent","j","items","item","str","noteNumber","parseResult","toUpperCase","toLowerCase","toLocaleLowerCase","parseFloat","replace","forEach","fee","toFixed","exec","op","quantity","parseInt","transactionValue","deal","price","average","note","Math","fround","abs","fill","map","index","a","module","exports","require","__webpack_module_cache__","__webpack_exports__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","call"],"sourceRoot":""}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "parser-de-notas-de-corretagem",
3
+ "version": "0.0.1",
4
+ "description": "Parse Brazilian brokerage notes PDFs (Inter and Clear holders available)",
5
+ "main": "notes-parser.js",
6
+ "types": "notes-parser.d.ts",
7
+ "scripts": {
8
+ "test": "jest --forceExit --runInBand --detectOpenHandles",
9
+ "build": "tsc --declaration",
10
+ "pack": "webpack --mode production",
11
+ "publish": "npm publish ./dist --access=public",
12
+ "update-assets": "npm run build && node dist/scripts/update.js"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/planetsLightningArrester/leitor-de-notas-de-corretagem.git"
17
+ },
18
+ "keywords": [],
19
+ "author": "Planet's Lightning Arrester",
20
+ "license": "GNU GPLv3",
21
+ "bugs": {
22
+ "url": "https://github.com/planetsLightningArrester/parser-de-notas-de-corretagem/issues"
23
+ },
24
+ "homepage": "https://github.com/planetsLightningArrester/parser-de-notas-de-corretagem#readme",
25
+ "engines": {
26
+ "npm": ">=7.0.0",
27
+ "node": ">=17.0.0"
28
+ },
29
+ "dependencies": {
30
+ "axios": "^0.27.2",
31
+ "pdfjs-dist": "^2.16.105"
32
+ },
33
+ "devDependencies": {
34
+ "@babel/core": "^7.16.0",
35
+ "@babel/preset-env": "^7.16.0",
36
+ "@babel/preset-typescript": "^7.16.0",
37
+ "@types/jest": "^29.0.3",
38
+ "@types/node": "^18.7.18",
39
+ "@types/webpack": "^5.28.0",
40
+ "@types/webpack-node-externals": "^2.5.3",
41
+ "babel-jest": "^29.0.3",
42
+ "copy-webpack-plugin": "^11.0.0",
43
+ "jest": "^29.0.3",
44
+ "ts-jest": "^29.0.1",
45
+ "ts-loader": "^9.2.6",
46
+ "ts-node": "^10.4.0",
47
+ "typescript": "^4.5.3",
48
+ "webpack": "^5.74.0",
49
+ "webpack-cli": "^4.10.0",
50
+ "webpack-node-externals": "^3.0.0"
51
+ }
52
+ }