UNPKG

intl-watcher

Version:

Automated translation key extraction and dictionary management plugin for Next.js

75 lines (71 loc) 3.57 kB
import dedent from "dedent"; import pc from "picocolors"; import { ERROR, log, WARN } from "./logger.js"; import { getCommonPrefix } from "./utils.js"; const Severity = { Error: "Error", Warn: "Warn" }; function getDiagnosticConfig(severity) { return severity === Severity.Error ? { label: ERROR, logger: log.error, formatter: pc.red } : { label: WARN, logger: log.warn, formatter: pc.yellow }; } function generateHeader(sourceFile, targetLine, targetColumn) { const projectFiles = sourceFile.getProject().getSourceFiles(); const rootDirectory = getCommonPrefix(projectFiles.map((file) => file.getFilePath())); const filePath = sourceFile.getFilePath().substring(rootDirectory.length); return `${filePath}:${targetLine}:${targetColumn} ${"\u2501".repeat( Math.max(0, 100 - filePath.length - targetLine.toString().length - targetColumn.toString().length - 2) )}`; } function buildSnippet(contextNode, targetNode) { const sourceFile = contextNode.getSourceFile(); const { line: contextStartLine, column: contextStartColumn } = sourceFile.getLineAndColumnAtPos( contextNode.getStart() ); const { line: targetLine, column: targetColumn } = sourceFile.getLineAndColumnAtPos(targetNode.getStart()); const contextTextLines = contextNode.getText().split("\n"); const targetRelativeLineIndex = targetLine - contextStartLine; const maxLineNumber = contextStartLine + contextTextLines.length - 1; const lineNumberPadding = maxLineNumber.toString().length; const snippetWithUnderline = contextTextLines.map((line, index) => { const expandedLine = expandTabs(line); const currentLineNumber = (contextStartLine + index).toString().padStart(lineNumberPadding); if (index === targetRelativeLineIndex) { const leadingText = targetLine === contextStartLine ? line.substring(contextStartColumn - 1, targetColumn - 1) : line.substring(0, targetColumn - 1); const expandedLeadingText = expandTabs(leadingText); const effectiveOffset = expandedLeadingText.length; const targetText = targetNode.getText(); const firstLineOfTarget = targetText.split("\n")[0]; const expandedTargetFirstLine = expandTabs(firstLineOfTarget); const underline = " ".repeat(effectiveOffset) + pc.red("^".repeat(expandedTargetFirstLine.length)); return `${currentLineNumber} | ${expandedLine} ${" ".repeat(lineNumberPadding)} | ${underline}`; } return `${currentLineNumber} | ${expandedLine}`; }).join("\n"); return snippetWithUnderline.split("\n").map((line) => `${" ".repeat(8)}${line}`).join("\n"); } function formatSuggestions(suggestions) { return suggestions.join("\n").replace(/\n/g, ` ${" ".repeat(10)}`); } function printDiagnostic(targetNode, contextNode, severity, detailedMessage, ...suggestions) { const sourceFile = contextNode.getSourceFile(); const { line: targetLine, column: targetColumn } = sourceFile.getLineAndColumnAtPos(targetNode.getStart()); const header = generateHeader(sourceFile, targetLine, targetColumn); const snippet = buildSnippet(contextNode, targetNode); const formattedSuggestions = formatSuggestions(suggestions); const { label, logger, formatter } = getDiagnosticConfig(severity); const diagnosticMessage = dedent` ${header} ${label} ${formatter(detailedMessage)} ${snippet} ${pc.green(pc.bold("\u2139"))} ${pc.green(formattedSuggestions)} `; logger(diagnosticMessage); log.info(); } function expandTabs(line, tabSize = 2) { return line.replace(/\t/g, " ".repeat(tabSize)); } export { Severity, printDiagnostic };