@parcel/codeframe
Advanced tools
+111
-51
@@ -12,2 +12,6 @@ "use strict"; | ||
| var _stringWidth = _interopRequireDefault(require("string-width")); | ||
| var _sliceAnsi = _interopRequireDefault(require("slice-ansi")); | ||
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -18,2 +22,3 @@ | ||
| const TAB_REPLACEMENT = ' '; | ||
| const DEFAULT_TERMINAL_WIDTH = 80; | ||
@@ -31,4 +36,5 @@ const highlightSyntax = (txt, lang) => { | ||
| function codeFrame(code, highlights, // $FlowFixMe | ||
| inputOpts = {}) { | ||
| function codeFrame(code, highlights, inputOpts = {}) { | ||
| var _inputOpts$maxLines; | ||
| if (highlights.length < 1) return ''; | ||
@@ -39,3 +45,4 @@ let opts = { | ||
| language: inputOpts.language, | ||
| maxLines: inputOpts.maxLines !== undefined ? inputOpts.maxLines : 12, | ||
| maxLines: (_inputOpts$maxLines = inputOpts.maxLines) !== null && _inputOpts$maxLines !== void 0 ? _inputOpts$maxLines : 12, | ||
| terminalWidth: inputOpts.terminalWidth || DEFAULT_TERMINAL_WIDTH, | ||
| padding: inputOpts.padding || { | ||
@@ -45,3 +52,3 @@ before: 1, | ||
| } | ||
| }; | ||
| }; // Highlights messages and prefixes when colors are enabled | ||
@@ -56,4 +63,5 @@ const highlighter = (s, bold) => { | ||
| return s; | ||
| }; | ||
| }; // Prefix lines with the line number | ||
| const lineNumberPrefixer = params => { | ||
@@ -81,5 +89,7 @@ let { | ||
| }; | ||
| }); | ||
| }); // Find first and last highlight | ||
| let firstHighlight = highlights.length > 1 ? highlights.sort((a, b) => a.start.line - b.start.line)[0] : highlights[0]; | ||
| let lastHighlight = highlights.length > 1 ? highlights.sort((a, b) => b.end.line - a.end.line)[0] : highlights[0]; | ||
| let lastHighlight = highlights.length > 1 ? highlights.sort((a, b) => b.end.line - a.end.line)[0] : highlights[0]; // Calculate first and last line index of codeframe | ||
| let startLine = firstHighlight.start.line - opts.padding.before; | ||
@@ -89,64 +99,114 @@ startLine = startLine < 0 ? 0 : startLine; | ||
| endLine = endLine - startLine > opts.maxLines ? startLine + opts.maxLines - 1 : endLine; | ||
| let endLineString = endLine.toString(10); | ||
| let resultLines = []; | ||
| let endLineString = endLine.toString(10); // Split input into lines and highlight syntax | ||
| let lines = code.split(NEWLINE); | ||
| let syntaxHighlightedLines = (opts.syntaxHighlighting ? highlightSyntax(code, opts.language) : code).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).split(NEWLINE); | ||
| let syntaxHighlightedLines = (opts.syntaxHighlighting ? highlightSyntax(code, opts.language) : code).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).split(NEWLINE); // Loop over all lines and create codeframe | ||
| for (let i = startLine; i < lines.length; i++) { | ||
| if (i > endLine) break; | ||
| let originalLine = lines[i]; | ||
| let syntaxHighlightedLine = syntaxHighlightedLines[i]; | ||
| let foundHighlights = highlights.filter(highlight => highlight.start.line <= i && highlight.end.line >= i); | ||
| let resultLines = []; | ||
| for (let currentLineIndex = startLine; currentLineIndex < syntaxHighlightedLines.length; currentLineIndex++) { | ||
| if (currentLineIndex > endLine) break; | ||
| if (currentLineIndex > syntaxHighlightedLines.length - 1) break; // Find highlights that need to get rendered on the current line | ||
| let lineHighlights = highlights.filter(highlight => highlight.start.line <= currentLineIndex && highlight.end.line >= currentLineIndex).sort((a, b) => (a.start.line < currentLineIndex ? 0 : a.start.column) - (b.start.line < currentLineIndex ? 0 : b.start.column)); // Check if this line has a full line highlight | ||
| let isWholeLine = lineHighlights.length && !!lineHighlights.find(h => h.start.line < currentLineIndex && h.end.line > currentLineIndex); | ||
| let lineLengthLimit = opts.terminalWidth > endLineString.length + 7 ? opts.terminalWidth - (endLineString.length + 5) : 10; // Split the line into line parts that will fit the provided terminal width | ||
| let colOffset = 0; | ||
| let lineEndCol = lineLengthLimit; | ||
| let syntaxHighlightedLine = syntaxHighlightedLines[currentLineIndex]; | ||
| if ((0, _stringWidth.default)(syntaxHighlightedLine) > lineLengthLimit) { | ||
| if (lineHighlights.length > 0) { | ||
| if (lineHighlights[0].start.line === currentLineIndex) { | ||
| colOffset = lineHighlights[0].start.column - 5; | ||
| } else if (lineHighlights[0].end.line === currentLineIndex) { | ||
| colOffset = lineHighlights[0].end.column - 5; | ||
| } | ||
| } | ||
| colOffset = colOffset > 0 ? colOffset : 0; | ||
| lineEndCol = colOffset + lineLengthLimit; | ||
| syntaxHighlightedLine = (0, _sliceAnsi.default)(syntaxHighlightedLine, colOffset, lineEndCol); | ||
| } // Write the syntax highlighted line part | ||
| resultLines.push(lineNumberPrefixer({ | ||
| lineNumber: (i + 1).toString(10), | ||
| lineNumber: (currentLineIndex + 1).toString(10), | ||
| endLine: endLineString, | ||
| isHighlighted: foundHighlights.length > 0 | ||
| isHighlighted: lineHighlights.length > 0 | ||
| }) + syntaxHighlightedLine); | ||
| let lineWidth = (0, _stringWidth.default)(syntaxHighlightedLine); | ||
| let highlightLine = ''; | ||
| if (foundHighlights.length > 0) { | ||
| let highlightLine = lineNumberPrefixer({ | ||
| endLine: endLineString, | ||
| isHighlighted: true | ||
| }); | ||
| let isWholeLine = !!foundHighlights.find(h => h.start.line < i && h.end.line > i); | ||
| if (isWholeLine) { | ||
| highlightLine = highlighter('^'.repeat(lineWidth)); | ||
| } else if (lineHighlights.length > 0) { | ||
| let lastCol = 0; | ||
| let highlight = null; | ||
| let highlightHasEnded = false; | ||
| if (isWholeLine) { | ||
| // If there's a whole line highlight | ||
| // don't even bother creating seperate highlight | ||
| highlightLine += highlighter('^'.repeat(originalLine.replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length)); | ||
| } else { | ||
| let sortedColumns = foundHighlights.length > 1 ? foundHighlights.sort((a, b) => (a.start.line < i ? 0 : a.start.column) - (b.start.line < i ? 0 : b.start.column)) : foundHighlights; | ||
| let lastCol = 0; | ||
| for (let highlightIndex = 0; highlightIndex < lineHighlights.length; highlightIndex++) { | ||
| // Set highlight to current highlight | ||
| highlight = lineHighlights[highlightIndex]; | ||
| highlightHasEnded = false; // Calculate the startColumn and get the real width by doing a substring of the original | ||
| // line and replacing tabs with our tab replacement to support tab handling | ||
| for (let col of sortedColumns) { | ||
| let startCol = col.start.line === i ? col.start.column : 0; | ||
| let endCol = (col.end.line === i ? col.end.column : originalLine.length - (lastCol || 1)) + 1; | ||
| let startCol = 0; | ||
| if (startCol - lastCol > 0) { | ||
| let whitespace = originalLine.substring(lastCol, startCol).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).replace(/\S/g, ' '); | ||
| highlightLine += whitespace; | ||
| } | ||
| if (highlight.start.line === currentLineIndex && highlight.start.column > colOffset) { | ||
| startCol = lines[currentLineIndex].substring(colOffset, highlight.start.column).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; | ||
| } // Calculate the endColumn and get the real width by doing a substring of the original | ||
| // line and replacing tabs with our tab replacement to support tab handling | ||
| let highlightStartColumn = lastCol >= startCol ? lastCol : startCol; | ||
| if (endCol - highlightStartColumn > 0) { | ||
| let renderedHighlightLength = originalLine.substring(highlightStartColumn, endCol).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; | ||
| highlightLine += highlighter('^'.repeat(renderedHighlightLength)); | ||
| lastCol = endCol; | ||
| let endCol = lineWidth - 1; | ||
| if (highlight.end.line === currentLineIndex) { | ||
| endCol = lines[currentLineIndex].substring(colOffset, highlight.end.column).replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; // If the endCol is too big for this line part, trim it so we can handle it in the next one | ||
| if (endCol > lineWidth) { | ||
| endCol = lineWidth - 1; | ||
| } | ||
| } | ||
| let endsWithFullLine = !!sortedColumns.find(h => h.end.line > i); | ||
| highlightHasEnded = true; | ||
| } // If endcol is smaller than lastCol it overlaps with another highlight and is no longer visible, we can skip those | ||
| if (!endsWithFullLine) { | ||
| let sortedByEnd = sortedColumns.sort((a, b) => a.end.column - b.end.column); | ||
| let lastHighlightForColumn = sortedByEnd[sortedByEnd.length - 1]; | ||
| if (lastHighlightForColumn.message) { | ||
| highlightLine += ' ' + highlighter(lastHighlightForColumn.message, true); | ||
| } | ||
| if (endCol >= lastCol) { | ||
| let characters = endCol - startCol + 1; | ||
| if (startCol > lastCol) { | ||
| // startCol is before lastCol, so add spaces as padding before the highlight indicators | ||
| highlightLine += ' '.repeat(startCol - lastCol); | ||
| } else if (lastCol > startCol) { | ||
| // If last column is larger than the start, there's overlap in highlights | ||
| // This line adjusts the characters count to ensure we don't add too many characters | ||
| characters += startCol - lastCol; | ||
| } // Append the highlight indicators | ||
| highlightLine += highlighter('^'.repeat(characters)); // Set the lastCol equal to character count between start of line part and highlight end-column | ||
| lastCol = endCol + 1; | ||
| } // There's no point in processing more highlights if we reached the end of the line | ||
| if (endCol >= lineEndCol - 1) { | ||
| break; | ||
| } | ||
| } // Append the highlight message if the current highlights ends on this line part | ||
| if (highlight && highlight.message && highlightHasEnded) { | ||
| highlightLine += ' ' + highlighter(highlight.message, true); | ||
| } | ||
| } | ||
| resultLines.push(highlightLine); | ||
| if (highlightLine) { | ||
| resultLines.push(lineNumberPrefixer({ | ||
| endLine: endLineString, | ||
| isHighlighted: true | ||
| }) + highlightLine); | ||
| } | ||
@@ -153,0 +213,0 @@ } |
+8
-3
| { | ||
| "name": "@parcel/codeframe", | ||
| "version": "2.0.0-alpha.3.1", | ||
| "version": "2.0.0-beta.1", | ||
| "description": "Blazing fast, zero configuration web application bundler", | ||
@@ -20,5 +20,10 @@ "license": "MIT", | ||
| "chalk": "^2.4.2", | ||
| "emphasize": "^2.1.0" | ||
| "emphasize": "^2.1.0", | ||
| "slice-ansi": "^4.0.0", | ||
| "string-width": "^4.2.0" | ||
| }, | ||
| "gitHead": "291f3e6815a1a857a6165fafb1691ceeb878b8f6" | ||
| "devDependencies": { | ||
| "strip-ansi": "^6.0.0" | ||
| }, | ||
| "gitHead": "74335525be92e23bac4ed1bf30595443cfb238e3" | ||
| } |
+153
-87
@@ -6,15 +6,11 @@ // @flow | ||
| import emphasize from 'emphasize'; | ||
| import stringWidth from 'string-width'; | ||
| import sliceAnsi from 'slice-ansi'; | ||
| type CodeFramePadding = {| | ||
| before: number, | ||
| after: number | ||
| after: number, | ||
| |}; | ||
| type CodeFrameOptionsInput = {| | ||
| useColor?: boolean, | ||
| maxLines?: number, | ||
| padding?: CodeFramePadding, | ||
| syntaxHighlighting?: boolean, | ||
| language?: string | ||
| |}; | ||
| type CodeFrameOptionsInput = $Shape<CodeFrameOptions>; | ||
@@ -26,3 +22,4 @@ type CodeFrameOptions = {| | ||
| padding: CodeFramePadding, | ||
| language?: string | ||
| terminalWidth: number, | ||
| language?: string, | ||
| |}; | ||
@@ -33,2 +30,3 @@ | ||
| const TAB_REPLACEMENT = ' '; | ||
| const DEFAULT_TERMINAL_WIDTH = 80; | ||
@@ -50,4 +48,3 @@ const highlightSyntax = (txt: string, lang?: string): string => { | ||
| highlights: Array<DiagnosticCodeHighlight>, | ||
| // $FlowFixMe | ||
| inputOpts: CodeFrameOptionsInput = {} | ||
| inputOpts: CodeFrameOptionsInput = {}, | ||
| ): string { | ||
@@ -60,9 +57,11 @@ if (highlights.length < 1) return ''; | ||
| language: inputOpts.language, | ||
| maxLines: inputOpts.maxLines !== undefined ? inputOpts.maxLines : 12, | ||
| maxLines: inputOpts.maxLines ?? 12, | ||
| terminalWidth: inputOpts.terminalWidth || DEFAULT_TERMINAL_WIDTH, | ||
| padding: inputOpts.padding || { | ||
| before: 1, | ||
| after: 2 | ||
| } | ||
| after: 2, | ||
| }, | ||
| }; | ||
| // Highlights messages and prefixes when colors are enabled | ||
| const highlighter = (s: string, bold?: boolean) => { | ||
@@ -77,6 +76,7 @@ if (opts.useColor) { | ||
| // Prefix lines with the line number | ||
| const lineNumberPrefixer = (params: {| | ||
| lineNumber?: string, | ||
| endLine: string, | ||
| isHighlighted: boolean | ||
| isHighlighted: boolean, | ||
| |}) => { | ||
@@ -97,12 +97,13 @@ let {lineNumber, endLine, isHighlighted} = params; | ||
| column: h.start.column - 1, | ||
| line: h.start.line - 1 | ||
| line: h.start.line - 1, | ||
| }, | ||
| end: { | ||
| column: h.end.column - 1, | ||
| line: h.end.line - 1 | ||
| line: h.end.line - 1, | ||
| }, | ||
| message: h.message | ||
| message: h.message, | ||
| }; | ||
| }); | ||
| // Find first and last highlight | ||
| let firstHighlight = | ||
@@ -117,2 +118,3 @@ highlights.length > 1 | ||
| // Calculate first and last line index of codeframe | ||
| let startLine = firstHighlight.start.line - opts.padding.before; | ||
@@ -127,3 +129,3 @@ startLine = startLine < 0 ? 0 : startLine; | ||
| let resultLines = []; | ||
| // Split input into lines and highlight syntax | ||
| let lines = code.split(NEWLINE); | ||
@@ -136,91 +138,155 @@ let syntaxHighlightedLines = (opts.syntaxHighlighting | ||
| .split(NEWLINE); | ||
| for (let i = startLine; i < lines.length; i++) { | ||
| if (i > endLine) break; | ||
| let originalLine: string = lines[i]; | ||
| let syntaxHighlightedLine = syntaxHighlightedLines[i]; | ||
| // Loop over all lines and create codeframe | ||
| let resultLines = []; | ||
| for ( | ||
| let currentLineIndex = startLine; | ||
| currentLineIndex < syntaxHighlightedLines.length; | ||
| currentLineIndex++ | ||
| ) { | ||
| if (currentLineIndex > endLine) break; | ||
| if (currentLineIndex > syntaxHighlightedLines.length - 1) break; | ||
| let foundHighlights = highlights.filter( | ||
| highlight => highlight.start.line <= i && highlight.end.line >= i | ||
| ); | ||
| // Find highlights that need to get rendered on the current line | ||
| let lineHighlights = highlights | ||
| .filter( | ||
| highlight => | ||
| highlight.start.line <= currentLineIndex && | ||
| highlight.end.line >= currentLineIndex, | ||
| ) | ||
| .sort( | ||
| (a, b) => | ||
| (a.start.line < currentLineIndex ? 0 : a.start.column) - | ||
| (b.start.line < currentLineIndex ? 0 : b.start.column), | ||
| ); | ||
| // Check if this line has a full line highlight | ||
| let isWholeLine = | ||
| lineHighlights.length && | ||
| !!lineHighlights.find( | ||
| h => h.start.line < currentLineIndex && h.end.line > currentLineIndex, | ||
| ); | ||
| let lineLengthLimit = | ||
| opts.terminalWidth > endLineString.length + 7 | ||
| ? opts.terminalWidth - (endLineString.length + 5) | ||
| : 10; | ||
| // Split the line into line parts that will fit the provided terminal width | ||
| let colOffset = 0; | ||
| let lineEndCol = lineLengthLimit; | ||
| let syntaxHighlightedLine = syntaxHighlightedLines[currentLineIndex]; | ||
| if (stringWidth(syntaxHighlightedLine) > lineLengthLimit) { | ||
| if (lineHighlights.length > 0) { | ||
| if (lineHighlights[0].start.line === currentLineIndex) { | ||
| colOffset = lineHighlights[0].start.column - 5; | ||
| } else if (lineHighlights[0].end.line === currentLineIndex) { | ||
| colOffset = lineHighlights[0].end.column - 5; | ||
| } | ||
| } | ||
| colOffset = colOffset > 0 ? colOffset : 0; | ||
| lineEndCol = colOffset + lineLengthLimit; | ||
| syntaxHighlightedLine = sliceAnsi( | ||
| syntaxHighlightedLine, | ||
| colOffset, | ||
| lineEndCol, | ||
| ); | ||
| } | ||
| // Write the syntax highlighted line part | ||
| resultLines.push( | ||
| lineNumberPrefixer({ | ||
| lineNumber: (i + 1).toString(10), | ||
| lineNumber: (currentLineIndex + 1).toString(10), | ||
| endLine: endLineString, | ||
| isHighlighted: foundHighlights.length > 0 | ||
| }) + syntaxHighlightedLine | ||
| isHighlighted: lineHighlights.length > 0, | ||
| }) + syntaxHighlightedLine, | ||
| ); | ||
| if (foundHighlights.length > 0) { | ||
| let highlightLine = lineNumberPrefixer({ | ||
| endLine: endLineString, | ||
| isHighlighted: true | ||
| }); | ||
| let lineWidth = stringWidth(syntaxHighlightedLine); | ||
| let highlightLine = ''; | ||
| if (isWholeLine) { | ||
| highlightLine = highlighter('^'.repeat(lineWidth)); | ||
| } else if (lineHighlights.length > 0) { | ||
| let lastCol = 0; | ||
| let highlight = null; | ||
| let highlightHasEnded = false; | ||
| let isWholeLine = !!foundHighlights.find( | ||
| h => h.start.line < i && h.end.line > i | ||
| ); | ||
| for ( | ||
| let highlightIndex = 0; | ||
| highlightIndex < lineHighlights.length; | ||
| highlightIndex++ | ||
| ) { | ||
| // Set highlight to current highlight | ||
| highlight = lineHighlights[highlightIndex]; | ||
| highlightHasEnded = false; | ||
| if (isWholeLine) { | ||
| // If there's a whole line highlight | ||
| // don't even bother creating seperate highlight | ||
| highlightLine += highlighter( | ||
| '^'.repeat( | ||
| originalLine.replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length | ||
| ) | ||
| ); | ||
| } else { | ||
| let sortedColumns = | ||
| foundHighlights.length > 1 | ||
| ? foundHighlights.sort( | ||
| (a, b) => | ||
| (a.start.line < i ? 0 : a.start.column) - | ||
| (b.start.line < i ? 0 : b.start.column) | ||
| ) | ||
| : foundHighlights; | ||
| // Calculate the startColumn and get the real width by doing a substring of the original | ||
| // line and replacing tabs with our tab replacement to support tab handling | ||
| let startCol = 0; | ||
| if ( | ||
| highlight.start.line === currentLineIndex && | ||
| highlight.start.column > colOffset | ||
| ) { | ||
| startCol = lines[currentLineIndex] | ||
| .substring(colOffset, highlight.start.column) | ||
| .replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; | ||
| } | ||
| let lastCol = 0; | ||
| for (let col of sortedColumns) { | ||
| let startCol = col.start.line === i ? col.start.column : 0; | ||
| let endCol = | ||
| (col.end.line === i | ||
| ? col.end.column | ||
| : originalLine.length - (lastCol || 1)) + 1; | ||
| // Calculate the endColumn and get the real width by doing a substring of the original | ||
| // line and replacing tabs with our tab replacement to support tab handling | ||
| let endCol = lineWidth - 1; | ||
| if (highlight.end.line === currentLineIndex) { | ||
| endCol = lines[currentLineIndex] | ||
| .substring(colOffset, highlight.end.column) | ||
| .replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; | ||
| if (startCol - lastCol > 0) { | ||
| let whitespace = originalLine | ||
| .substring(lastCol, startCol) | ||
| .replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT) | ||
| .replace(/\S/g, ' '); | ||
| highlightLine += whitespace; | ||
| // If the endCol is too big for this line part, trim it so we can handle it in the next one | ||
| if (endCol > lineWidth) { | ||
| endCol = lineWidth - 1; | ||
| } | ||
| let highlightStartColumn = lastCol >= startCol ? lastCol : startCol; | ||
| if (endCol - highlightStartColumn > 0) { | ||
| let renderedHighlightLength = originalLine | ||
| .substring(highlightStartColumn, endCol) | ||
| .replace(TAB_REPLACE_REGEX, TAB_REPLACEMENT).length; | ||
| highlightLine += highlighter('^'.repeat(renderedHighlightLength)); | ||
| lastCol = endCol; | ||
| } | ||
| highlightHasEnded = true; | ||
| } | ||
| let endsWithFullLine = !!sortedColumns.find(h => h.end.line > i); | ||
| if (!endsWithFullLine) { | ||
| let sortedByEnd = sortedColumns.sort( | ||
| (a, b) => a.end.column - b.end.column | ||
| ); | ||
| // If endcol is smaller than lastCol it overlaps with another highlight and is no longer visible, we can skip those | ||
| if (endCol >= lastCol) { | ||
| let characters = endCol - startCol + 1; | ||
| if (startCol > lastCol) { | ||
| // startCol is before lastCol, so add spaces as padding before the highlight indicators | ||
| highlightLine += ' '.repeat(startCol - lastCol); | ||
| } else if (lastCol > startCol) { | ||
| // If last column is larger than the start, there's overlap in highlights | ||
| // This line adjusts the characters count to ensure we don't add too many characters | ||
| characters += startCol - lastCol; | ||
| } | ||
| let lastHighlightForColumn = sortedByEnd[sortedByEnd.length - 1]; | ||
| if (lastHighlightForColumn.message) { | ||
| highlightLine += | ||
| ' ' + highlighter(lastHighlightForColumn.message, true); | ||
| } | ||
| // Append the highlight indicators | ||
| highlightLine += highlighter('^'.repeat(characters)); | ||
| // Set the lastCol equal to character count between start of line part and highlight end-column | ||
| lastCol = endCol + 1; | ||
| } | ||
| // There's no point in processing more highlights if we reached the end of the line | ||
| if (endCol >= lineEndCol - 1) { | ||
| break; | ||
| } | ||
| } | ||
| resultLines.push(highlightLine); | ||
| // Append the highlight message if the current highlights ends on this line part | ||
| if (highlight && highlight.message && highlightHasEnded) { | ||
| highlightLine += ' ' + highlighter(highlight.message, true); | ||
| } | ||
| } | ||
| if (highlightLine) { | ||
| resultLines.push( | ||
| lineNumberPrefixer({ | ||
| endLine: endLineString, | ||
| isHighlighted: true, | ||
| }) + highlightLine, | ||
| ); | ||
| } | ||
| } | ||
@@ -227,0 +293,0 @@ |
+287
-131
@@ -15,8 +15,8 @@ import assert from 'assert'; | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| } | ||
| line: 1, | ||
| }, | ||
| }, | ||
@@ -26,11 +26,11 @@ { | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 5, | ||
| line: 1 | ||
| } | ||
| } | ||
| line: 1, | ||
| }, | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -50,8 +50,8 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| } | ||
| line: 1, | ||
| }, | ||
| }, | ||
@@ -61,11 +61,11 @@ { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 10, | ||
| line: 2 | ||
| } | ||
| } | ||
| line: 2, | ||
| }, | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -87,8 +87,8 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| } | ||
| line: 1, | ||
| }, | ||
| }, | ||
@@ -98,8 +98,8 @@ { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 10, | ||
| line: 2 | ||
| } | ||
| line: 2, | ||
| }, | ||
| }, | ||
@@ -109,11 +109,11 @@ { | ||
| column: 4, | ||
| line: 2 | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 2 | ||
| } | ||
| } | ||
| line: 2, | ||
| }, | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -135,8 +135,8 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| } | ||
| line: 1, | ||
| }, | ||
| }, | ||
@@ -146,8 +146,8 @@ { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 10, | ||
| line: 2 | ||
| } | ||
| line: 2, | ||
| }, | ||
| }, | ||
@@ -157,11 +157,11 @@ { | ||
| column: 4, | ||
| line: 2 | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 12, | ||
| line: 2 | ||
| } | ||
| } | ||
| line: 2, | ||
| }, | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -183,12 +183,12 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 6, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -209,9 +209,9 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -221,12 +221,12 @@ { | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 6, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'this should be printed' | ||
| } | ||
| message: 'this should be printed', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -247,9 +247,9 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -259,12 +259,12 @@ { | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'this should be printed' | ||
| } | ||
| message: 'this should be printed', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -285,9 +285,9 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -297,9 +297,9 @@ { | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'this should be printed' | ||
| message: 'this should be printed', | ||
| }, | ||
@@ -309,12 +309,12 @@ { | ||
| column: 3, | ||
| line: 2 | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 3 | ||
| line: 3, | ||
| }, | ||
| message: 'message line 2' | ||
| } | ||
| message: 'message line 2', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -338,9 +338,9 @@ | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -350,9 +350,9 @@ { | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'this should be printed' | ||
| message: 'this should be printed', | ||
| }, | ||
@@ -362,12 +362,12 @@ { | ||
| column: 3, | ||
| line: 2 | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 3 | ||
| line: 3, | ||
| }, | ||
| message: 'message line 2' | ||
| } | ||
| message: 'message line 2', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -391,10 +391,10 @@ | ||
| column: 2, | ||
| line: 5 | ||
| line: 5, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 5 | ||
| line: 5, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
@@ -405,5 +405,5 @@ { | ||
| before: 2, | ||
| after: 4 | ||
| } | ||
| } | ||
| after: 4, | ||
| }, | ||
| }, | ||
| ); | ||
@@ -424,9 +424,9 @@ | ||
| column: 2, | ||
| line: 99 | ||
| line: 99, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 99 | ||
| line: 99, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -436,10 +436,10 @@ { | ||
| column: 2, | ||
| line: 100 | ||
| line: 100, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 100 | ||
| line: 100, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ]); | ||
@@ -458,9 +458,9 @@ | ||
| column: 2, | ||
| line: 7 | ||
| line: 7, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 7 | ||
| line: 7, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -470,10 +470,10 @@ { | ||
| column: 2, | ||
| line: 12 | ||
| line: 12, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 12 | ||
| line: 12, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ]); | ||
@@ -494,9 +494,9 @@ | ||
| column: 2, | ||
| line: 5 | ||
| line: 5, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 5 | ||
| line: 5, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -506,15 +506,15 @@ { | ||
| column: 2, | ||
| line: 12 | ||
| line: 12, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 20 | ||
| line: 20, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
| { | ||
| useColor: false, | ||
| maxLines: 10 | ||
| } | ||
| maxLines: 10, | ||
| }, | ||
| ); | ||
@@ -536,12 +536,12 @@ | ||
| column: 5, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 7, | ||
| line: 1 | ||
| column: 8, | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -551,3 +551,3 @@ | ||
| assert.equal(lines[0], '> 1 | hel lo wor ld'); | ||
| assert.equal(lines[1], '> | ^^^ test'); | ||
| assert.equal(lines[1], '> | ^^^^ test'); | ||
| assert.equal(lines[2], ' 2 | Enjoy thi s nice cod eframe'); | ||
@@ -563,9 +563,9 @@ }); | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 5, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| message: 'test', | ||
| }, | ||
@@ -575,12 +575,12 @@ { | ||
| column: 7, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 8, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -601,12 +601,12 @@ | ||
| column: 3, | ||
| line: 1 | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 2, | ||
| line: 3 | ||
| line: 3, | ||
| }, | ||
| message: 'test' | ||
| } | ||
| message: 'test', | ||
| }, | ||
| ], | ||
| {useColor: false} | ||
| {useColor: false}, | ||
| ); | ||
@@ -622,2 +622,158 @@ | ||
| }); | ||
| it('Should truncate long lines and print message', () => { | ||
| let originalLine = 'hello world '.repeat(1000); | ||
| let codeframeString = codeframe( | ||
| originalLine, | ||
| [ | ||
| { | ||
| start: { | ||
| column: 1000, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 1200, | ||
| line: 1, | ||
| }, | ||
| message: 'This is a message', | ||
| }, | ||
| ], | ||
| {useColor: false, terminalWidth: 25}, | ||
| ); | ||
| let lines = codeframeString.split(LINE_END); | ||
| assert.equal(lines.length, 2); | ||
| assert.equal(lines[0], '> 1 | d hello world hello'); | ||
| assert.equal(lines[1], '> | ^^^^^^^^^^^^^^ This is a message'); | ||
| }); | ||
| it('Truncation across multiple lines', () => { | ||
| let originalLine = | ||
| 'hello world '.repeat(100) + '\n' + 'new line '.repeat(100); | ||
| let codeframeString = codeframe( | ||
| originalLine, | ||
| [ | ||
| { | ||
| start: { | ||
| column: 15, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 400, | ||
| line: 1, | ||
| }, | ||
| message: 'This is the first line', | ||
| }, | ||
| { | ||
| start: { | ||
| column: 2, | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 100, | ||
| line: 2, | ||
| }, | ||
| message: 'This is the second line', | ||
| }, | ||
| ], | ||
| {useColor: false, terminalWidth: 25}, | ||
| ); | ||
| let lines = codeframeString.split(LINE_END); | ||
| assert.equal(lines.length, 4); | ||
| assert.equal(lines[0], '> 1 | ld hello world hell'); | ||
| assert.equal(lines[1], '> | ^^^^^^^^^^^^^^ This is the first line'); | ||
| assert.equal(lines[2], '> 2 | new line new line n'); | ||
| assert.equal(lines[3], '> | ^^^^^^^^^^^^^^^^^^ This is the second line'); | ||
| }); | ||
| it('Truncation across various types and positions of highlights', () => { | ||
| let originalLine = | ||
| 'hello world '.repeat(100) + '\n' + 'new line '.repeat(100); | ||
| let codeframeString = codeframe( | ||
| originalLine, | ||
| [ | ||
| { | ||
| start: { | ||
| column: 2, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 5, | ||
| line: 1, | ||
| }, | ||
| }, | ||
| { | ||
| start: { | ||
| column: 6, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 10, | ||
| line: 1, | ||
| }, | ||
| message: 'I have a message', | ||
| }, | ||
| { | ||
| start: { | ||
| column: 15, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 25, | ||
| line: 1, | ||
| }, | ||
| message: 'I also have a message', | ||
| }, | ||
| { | ||
| start: { | ||
| column: 2, | ||
| line: 2, | ||
| }, | ||
| end: { | ||
| column: 5, | ||
| line: 2, | ||
| }, | ||
| message: 'This is the second line', | ||
| }, | ||
| ], | ||
| {useColor: false, terminalWidth: 25}, | ||
| ); | ||
| let lines = codeframeString.split(LINE_END); | ||
| assert.equal(lines.length, 4); | ||
| assert.equal(lines[0], '> 1 | hello world hello w'); | ||
| assert.equal(lines[1], '> | ^^^^^^^^^ ^^^^^ I also have a message'); | ||
| assert.equal(lines[2], '> 2 | new line new line n'); | ||
| assert.equal(lines[3], '> | ^^^^ This is the second line'); | ||
| }); | ||
| it('Multi-line highlight w/ truncation', () => { | ||
| let originalLine = | ||
| 'hello world '.repeat(100) + '\n' + 'new line '.repeat(100); | ||
| let codeframeString = codeframe( | ||
| originalLine, | ||
| [ | ||
| { | ||
| start: { | ||
| column: 2, | ||
| line: 1, | ||
| }, | ||
| end: { | ||
| column: 151, | ||
| line: 2, | ||
| }, | ||
| message: 'I have a message', | ||
| }, | ||
| ], | ||
| {useColor: false, terminalWidth: 25}, | ||
| ); | ||
| let lines = codeframeString.split(LINE_END); | ||
| assert.equal(lines.length, 4); | ||
| assert.equal(lines[0], '> 1 | hello world hello w'); | ||
| assert.equal(lines[1], '> | ^^^^^^^^^^^^^^^^^^'); | ||
| assert.equal(lines[2], '> 2 | ew line new line ne'); | ||
| assert.equal(lines[3], '> | ^^^^^^ I have a message'); | ||
| }); | ||
| }); |
-2
| // @flow | ||
| export * from './src/codeframe'; |
36421
38.6%1106
27.86%4
100%1
Infinity%5
-16.67%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added