UNPKG

@fast-csv/parse

Version:
99 lines 4.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QuotedColumnParser = void 0; const ColumnFormatter_1 = require("./ColumnFormatter"); const Token_1 = require("../Token"); class QuotedColumnParser { parserOptions; columnFormatter; constructor(parserOptions) { this.parserOptions = parserOptions; this.columnFormatter = new ColumnFormatter_1.ColumnFormatter(parserOptions); } parse(scanner) { if (!scanner.hasMoreCharacters) { return null; } const originalCursor = scanner.cursor; const { foundClosingQuote, col } = this.gatherDataBetweenQuotes(scanner); if (!foundClosingQuote) { // reset the cursor to the original scanner.advanceTo(originalCursor); // if we didnt find a closing quote but we potentially have more data then skip the parsing // and return the original scanner. if (!scanner.hasMoreData) { throw new Error(`Parse Error: missing closing: '${this.parserOptions.quote || ''}' in line: at '${scanner.lineFromCursor.replace(/[\r\n]/g, "\\n'")}'`); } return null; } this.checkForMalformedColumn(scanner); return col; } gatherDataBetweenQuotes(scanner) { const { parserOptions } = this; let foundStartingQuote = false; let foundClosingQuote = false; const characters = []; let nextToken = scanner.nextCharacterToken; for (; !foundClosingQuote && nextToken !== null; nextToken = scanner.nextCharacterToken) { const isQuote = Token_1.Token.isTokenQuote(nextToken, parserOptions); // ignore first quote if (!foundStartingQuote && isQuote) { foundStartingQuote = true; } else if (foundStartingQuote) { if (Token_1.Token.isTokenEscapeCharacter(nextToken, parserOptions)) { // advance past the escape character so we can get the next one in line scanner.advancePastToken(nextToken); const tokenFollowingEscape = scanner.nextCharacterToken; // if the character following the escape is a quote character then just add // the quote and advance to that character if (tokenFollowingEscape !== null && (Token_1.Token.isTokenQuote(tokenFollowingEscape, parserOptions) || Token_1.Token.isTokenEscapeCharacter(tokenFollowingEscape, parserOptions))) { characters.push(tokenFollowingEscape.token); nextToken = tokenFollowingEscape; } else if (isQuote) { // if the escape is also a quote then we found our closing quote and finish early foundClosingQuote = true; } else { // other wise add the escape token to the characters since it wast escaping anything characters.push(nextToken.token); } } else if (isQuote) { // we found our closing quote! foundClosingQuote = true; } else { // add the token to the characters characters.push(nextToken.token); } } scanner.advancePastToken(nextToken); } return { col: this.columnFormatter.format(characters.join('')), foundClosingQuote }; } checkForMalformedColumn(scanner) { const { parserOptions } = this; const { nextNonSpaceToken } = scanner; if (nextNonSpaceToken) { const isNextTokenADelimiter = Token_1.Token.isTokenDelimiter(nextNonSpaceToken, parserOptions); const isNextTokenARowDelimiter = Token_1.Token.isTokenRowDelimiter(nextNonSpaceToken); if (!(isNextTokenADelimiter || isNextTokenARowDelimiter)) { // if the final quote was NOT followed by a column (,) or row(\n) delimiter then its a bad column // tldr: only part of the column was quoted const linePreview = scanner.lineFromCursor.substr(0, 10).replace(/[\r\n]/g, "\\n'"); throw new Error(`Parse Error: expected: '${parserOptions.escapedDelimiter}' OR new line got: '${nextNonSpaceToken.token}'. at '${linePreview}'`); } scanner.advanceToToken(nextNonSpaceToken); } else if (!scanner.hasMoreData) { scanner.advancePastLine(); } } } exports.QuotedColumnParser = QuotedColumnParser; //# sourceMappingURL=QuotedColumnParser.js.map