formatSassError.js 2.01 KB
"use strict";

const path = require("path");
const os = require("os");
const fs = require("fs");

// A typical sass error looks like this
const SassError = { // eslint-disable-line no-unused-vars
    message: "invalid property name",
    column: 14,
    line: 1,
    file: "stdin",
    status: 1
};

/**
 * Enhances the sass error with additional information about what actually went wrong.
 *
 * @param {SassError} err
 * @param {string} resourcePath
 */
function formatSassError(err, resourcePath) {
    // Instruct webpack to hide the JS stack from the console
    // Usually you're only interested in the SASS stack in this case.
    err.hideStack = true;

    // The file property is missing in rare cases.
    // No improvement in the error is possible.
    if (!err.file) {
        return;
    }

    let msg = err.message;

    if (err.file === "stdin") {
        err.file = resourcePath;
    }
    // node-sass returns UNIX-style paths
    err.file = path.normalize(err.file);

    // The 'Current dir' hint of node-sass does not help us, we're providing
    // additional information by reading the err.file property
    msg = msg.replace(/\s*Current dir:\s*/, "");

    err.message = getFileExcerptIfPossible(err) +
        msg.charAt(0).toUpperCase() + msg.slice(1) + os.EOL +
        "      in " + err.file + " (line " + err.line + ", column " + err.column + ")";
}

/**
 * Tries to get an excerpt of the file where the error happened.
 * Uses err.line and err.column.
 *
 * Returns an empty string if the excerpt could not be retrieved.
 *
 * @param {SassError} err
 * @returns {string}
 */
function getFileExcerptIfPossible(err) {
    try {
        const content = fs.readFileSync(err.file, "utf8");

        return os.EOL +
            content.split(os.EOL)[err.line - 1] + os.EOL +
            new Array(err.column - 1).join(" ") + "^" + os.EOL +
            "      ";
    } catch (err) {
        // If anything goes wrong here, we don't want any errors to be reported to the user
        return "";
    }
}

module.exports = formatSassError;