UNPKG

@blainehansen/macro-ts

Version:

An ergonomic typescript compiler that enables typesafe syntactic macros.

170 lines 7.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.formatDiagnostic = exports.formatDiagnostics = exports.SpanResult = exports.SpanWarning = exports.SpanError = exports.Span = void 0; const chalk = require("chalk"); const monads_1 = require("@ts-std/monads"); function Span(file, start, text, line, column) { return { file, start, end: start + text.length, line, column }; } exports.Span = Span; (function (Span) { function fromTsNode(sourceFile, { pos: start, end }) { const { line: zeroLine, character: column } = sourceFile.getLineAndCharacterOfPosition(start); const { text: source, fileName: filename } = sourceFile; return { file: { source, filename }, start, end, line: zeroLine + 1, column }; } Span.fromTsNode = fromTsNode; })(Span = exports.Span || (exports.Span = {})); function SpanError(region, title, paragraphs) { return { region, title, message: paragraphs.join("\n"), error: true }; } exports.SpanError = SpanError; function SpanWarning(region, title, paragraphs) { return { region, title, message: paragraphs.join("\n"), error: false }; } exports.SpanWarning = SpanWarning; var SpanResult; (function (SpanResult) { function Ok(value, warnings) { return (0, monads_1.Ok)({ value, warnings }); } SpanResult.Ok = Ok; function TsNodeErr(sourceFile, node, title, paragraphs) { return (0, monads_1.Err)({ errors: [SpanError(Span.fromTsNode(sourceFile, node), title, paragraphs)] }); } SpanResult.TsNodeErr = TsNodeErr; function Err(fileName, title, paragraphs) { return (0, monads_1.Err)({ errors: [SpanError(fileName, title, paragraphs)] }); } SpanResult.Err = Err; function checkSuccess(errors, warnings) { return [errors.length ? (0, monads_1.Err)(errors) : (0, monads_1.Ok)(undefined), warnings]; } SpanResult.checkSuccess = checkSuccess; class Context { sourceFile; errors = []; warnings = []; drop() { const errors = this.errors.splice(0, this.errors.length); const warnings = this.warnings.splice(0, this.warnings.length); return { errors, warnings }; } constructor(sourceFile) { this.sourceFile = sourceFile; } subsume(result) { if (result.is_ok()) { const { value, warnings } = result.value; if (warnings && warnings.length) this.warnings = this.warnings.concat(warnings); return (0, monads_1.Ok)(value); } const { errors, warnings } = result.error; if (warnings && warnings.length) this.warnings = this.warnings.concat(warnings); this.errors = this.errors.concat(errors); return (0, monads_1.Err)(undefined); } tsNodeWarn(node, title, paragraphs) { this.warnings.push(SpanWarning(Span.fromTsNode(this.sourceFile, node), title, paragraphs)); } warn(fileName, title, paragraphs) { this.warnings.push(SpanWarning(fileName, title, paragraphs)); } Err(node, title, ...paragraphs) { this.errors.push(SpanError(Span.fromTsNode(this.sourceFile, node), title, paragraphs)); return (0, monads_1.Err)(undefined); } } SpanResult.Context = Context; })(SpanResult = exports.SpanResult || (exports.SpanResult = {})); function formatDiagnostics(errors, warnings, lineWidth) { return errors.concat(warnings) .map(d => formatDiagnostic(d, lineWidth)) .join("\n\n\n") + "\n"; } exports.formatDiagnostics = formatDiagnostics; const info = chalk.blue.bold; const file = chalk.magentaBright.bold; function clean(s) { return s.replace(/\t/g, " "); } function formatDiagnostic({ region, title, message, error }, lineWidth) { const header = info(`-- ${title} ` + "-".repeat(lineWidth - (title.length + 4))); if (typeof region === "string") { const fileHeader = "\n" + " ".repeat(3) + file(region); return header + "\n" + fileHeader + formatMessage(message, "\n ", lineWidth); } const { file: { source, filename }, start, end, line, column } = region; const highlight = error ? chalk.red.bold : chalk.yellow.bold; const lineNumberWidth = line.toString().length; function makeGutter(lineNumber, error = false) { const insert = lineNumber !== undefined ? " ".repeat(lineNumberWidth - lineNumber.toString().length) + info(lineNumber) : " ".repeat(lineNumberWidth); return `\n ${insert} ${info("|")}${error ? highlight(">") : " "} `; } const blankGutter = makeGutter(); const margin = `\n${" ".repeat(lineNumberWidth)} `; const messageLine = "\n" + formatMessage(message, margin, lineWidth); const fileHeader = (filename ? "\n" + " ".repeat(lineNumberWidth + 3) + file(filename) : ""); let sourceLineStart = start; for (; sourceLineStart >= 0; sourceLineStart--) if (source[sourceLineStart] === "\n") break; const lines = []; let currentLineNumber = line; let currentLineStart = sourceLineStart; while (currentLineStart < end) { let currentLineEnd = source.indexOf("\n", currentLineStart + 1); if (currentLineEnd < 0) break; lines.push([currentLineNumber, source.slice(currentLineStart + 1, currentLineEnd)]); currentLineStart = currentLineEnd; currentLineNumber++; } switch (lines.length) { case 0: throw new Error("zuh?"); case 1: const [[, sourceLine]] = lines; const printSourceLine = clean(sourceLine); const pointerPrefix = " ".repeat(clean(sourceLine.slice(0, column)).length); const pointerWidth = end - start; const pointer = pointerPrefix + highlight("^".repeat(pointerWidth)); return header + "\n" + fileHeader + blankGutter + makeGutter(line) + printSourceLine + blankGutter + pointer + messageLine; default: return header + "\n" + fileHeader + blankGutter + lines.map(([lineNumber, line]) => makeGutter(lineNumber, true) + clean(line)).join("") + blankGutter + messageLine; } } exports.formatDiagnostic = formatDiagnostic; function formatMessage(message, margin, lineWidth) { const finalLineWidth = Math.min(lineWidth, 80); return message.split(/\n+/).map(paragraph => { const lines = []; let line = margin; const words = paragraph.split(/[ \t]+/); for (const word of words) { if (line.length + word.length + 1 > finalLineWidth) { lines.push(line); line = margin + " " + word; } else line += " " + word; } if (line !== margin) lines.push(line); return lines.join(""); }).join("\n"); } //# sourceMappingURL=message.js.map