From 65748ece396d0b38713783495d8a64f128d3992b Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Fri, 26 May 2023 04:01:12 +0300 Subject: [PATCH] fix: warning and error serialization --- src/Error.js | 39 ---------- src/Warning.js | 32 -------- src/index.js | 22 ++++-- src/utils.js | 67 ++++++++++++++--- .../__snapshots__/implementation.test.js.snap | 4 +- test/__snapshots__/loader.test.js.snap | 73 +++++++++++++------ 6 files changed, 120 insertions(+), 117 deletions(-) delete mode 100644 src/Error.js delete mode 100644 src/Warning.js diff --git a/src/Error.js b/src/Error.js deleted file mode 100644 index 45fa779c..00000000 --- a/src/Error.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * **PostCSS Syntax Error** - * - * Loader wrapper for postcss syntax errors - * - * @class SyntaxError - * @extends Error - * - * @param {Object} err CssSyntaxError - */ -class SyntaxError extends Error { - constructor(error) { - super(error); - - const { line, column, reason, plugin, file } = error; - - this.name = "SyntaxError"; - - this.message = `${this.name}\n\n`; - - if (typeof line !== "undefined") { - this.message += `(${line}:${column}) `; - } - - this.message += plugin ? `${plugin}: ` : ""; - this.message += file ? `${file} ` : " "; - this.message += `${reason}`; - - const code = error.showSourceCode(); - - if (code) { - this.message += `\n\n${code}\n`; - } - - this.stack = false; - } -} - -module.exports = SyntaxError; diff --git a/src/Warning.js b/src/Warning.js deleted file mode 100644 index 56e7684e..00000000 --- a/src/Warning.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * **PostCSS Plugin Warning** - * - * Loader wrapper for postcss plugin warnings (`root.messages`) - * - * @class Warning - * @extends Error - * - * @param {Object} warning PostCSS Warning - */ -class Warning extends Error { - constructor(warning) { - super(warning); - - const { text, line, column, plugin } = warning; - - this.name = "Warning"; - - this.message = `${this.name}\n\n`; - - if (typeof line !== "undefined") { - this.message += `(${line}:${column}) `; - } - - this.message += plugin ? `${plugin}: ` : ""; - this.message += `${text}`; - - this.stack = false; - } -} - -module.exports = Warning; diff --git a/src/index.js b/src/index.js index db014c1e..71ed8b1f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,7 @@ import path from "path"; -import { satisfies } from "semver"; import postcssPackage from "postcss/package.json"; -import Warning from "./Warning"; import schema from "./options.json"; import { loadConfig, @@ -14,6 +12,7 @@ import { findPackageJSONDir, getPostcssImplementation, reportError, + warningFactory, } from "./utils"; let hasExplicitDependencyOnPostCSS = false; @@ -40,9 +39,17 @@ export default async function loader(content, sourceMap, meta) { ? true : options.postcssOptions.config; - const postcssFactory = getPostcssImplementation(this, options.implementation); + let implementation; - if (!postcssFactory) { + try { + implementation = getPostcssImplementation(this, options.implementation); + } catch (error) { + callback(error); + + return; + } + + if (!implementation) { callback( new Error( `The Postcss implementation "${options.implementation}" not found` @@ -98,7 +105,8 @@ export default async function loader(content, sourceMap, meta) { meta && meta.ast && meta.ast.type === "postcss" && - satisfies(meta.ast.version, `^${postcssPackage.version}`) + // eslint-disable-next-line global-require + require("semver").satisfies(meta.ast.version, `^${postcssPackage.version}`) ) { ({ root } = meta.ast); } @@ -112,7 +120,7 @@ export default async function loader(content, sourceMap, meta) { let processor; try { - processor = postcssFactory(plugins); + processor = implementation(plugins); result = await processor.process(root || content, processOptions); } catch (error) { // Check postcss versions to avoid using PostCSS 7. @@ -175,7 +183,7 @@ export default async function loader(content, sourceMap, meta) { } for (const warning of result.warnings()) { - this.emitWarning(new Warning(warning)); + this.emitWarning(warningFactory(warning)); } for (const message of result.messages) { diff --git a/src/utils.js b/src/utils.js index d93e50c2..0c7423bb 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,8 +5,6 @@ import Module from "module"; import { klona } from "klona/full"; import { cosmiconfig, defaultLoaders } from "cosmiconfig"; -import SyntaxError from "./Error"; - const parentModule = module; const stat = (inputFileSystem, filePath) => @@ -541,15 +539,8 @@ function getPostcssImplementation(loaderContext, implementation) { if (!implementation || typeof implementation === "string") { const postcssImplPkg = implementation || "postcss"; - try { - // eslint-disable-next-line import/no-dynamic-require, global-require - resolvedImplementation = require(postcssImplPkg); - } catch (error) { - loaderContext.emitError(error); - - // eslint-disable-next-line consistent-return - return; - } + // eslint-disable-next-line import/no-dynamic-require, global-require + resolvedImplementation = require(postcssImplPkg); } // eslint-disable-next-line consistent-return @@ -562,12 +553,63 @@ function reportError(loaderContext, callback, error) { } if (error.name === "CssSyntaxError") { - callback(new SyntaxError(error)); + callback(syntaxErrorFactory(error)); } else { callback(error); } } +function warningFactory(obj) { + let message = ""; + + if (typeof obj.line !== "undefined") { + message += `(${obj.line}:${obj.column}) `; + } + + if (typeof obj.plugin !== "undefined") { + message += `from "${obj.plugin}" plugin: `; + } + + message += obj.text; + + if (obj.node) { + message += `\n\nCode:\n ${obj.node.toString()}\n`; + } + + const warning = new Error(message); + + warning.stack = null; + + return warning; +} + +function syntaxErrorFactory(obj) { + let message = "\nSyntaxError\n\n"; + + if (typeof obj.line !== "undefined") { + message += `(${obj.line}:${obj.column}) `; + } + + if (typeof obj.plugin !== "undefined") { + message += `from "${obj.plugin}" plugin: `; + } + + message += obj.file ? `${obj.file} ` : " "; + message += `${obj.reason}`; + + const code = obj.showSourceCode(); + + if (code) { + message += `\n\n${code}\n`; + } + + const error = new Error(message); + + error.stack = null; + + return error; +} + export { loadConfig, getPostcssOptions, @@ -577,4 +619,5 @@ export { findPackageJSONDir, getPostcssImplementation, reportError, + warningFactory, }; diff --git a/test/__snapshots__/implementation.test.js.snap b/test/__snapshots__/implementation.test.js.snap index 19a6a28d..b6700296 100644 --- a/test/__snapshots__/implementation.test.js.snap +++ b/test/__snapshots__/implementation.test.js.snap @@ -3,9 +3,7 @@ exports[`"implementation" option should throw error when unresolved package: errors 1`] = ` [ "ModuleBuildError: Module build failed (from \`replaced original path\`): -Error: The Postcss implementation "unresolved" not found", - "ModuleError: Module Error (from \`replaced original path\`): -(Emitted value instead of an instance of Error) Error: Cannot find module 'unresolved' from 'src/utils.js'", +NonErrorEmittedError: (Emitted value instead of an instance of Error) Error: Cannot find module 'unresolved' from 'src/utils.js'", ] `; diff --git a/test/__snapshots__/loader.test.js.snap b/test/__snapshots__/loader.test.js.snap index 0eb2767d..3eaab607 100644 --- a/test/__snapshots__/loader.test.js.snap +++ b/test/__snapshots__/loader.test.js.snap @@ -106,53 +106,77 @@ exports[`loader should emit warning using the "messages" API: errors 1`] = `[]`; exports[`loader should emit warning using the "messages" API: warnings 1`] = ` [ "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(10:3) from "postcss-plugin" plugin: -(10:3) postcss-plugin: ", +Code: + color: green +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(14:3) from "postcss-plugin" plugin: -(14:3) postcss-plugin: ", +Code: + color: blue +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(18:3) from "postcss-plugin" plugin: -(18:3) postcss-plugin: ", +Code: + -x-border-color: blue blue * +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(19:3) from "postcss-plugin" plugin: -(19:3) postcss-plugin: ", +Code: + -x-color: * #fafafa +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(23:3) from "postcss-plugin" plugin: -(23:3) postcss-plugin: ", +Code: + -z-border-color: blue blue * +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(24:3) from "postcss-plugin" plugin: -(24:3) postcss-plugin: ", +Code: + -z-color: * #fafafa +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(29:5) from "postcss-plugin" plugin: -(29:5) postcss-plugin: ", +Code: + width: 500px +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(2:3) from "postcss-plugin" plugin: -(2:3) postcss-plugin: ", +Code: + color: black +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(32:7) from "postcss-plugin" plugin: -(32:7) postcss-plugin: ", +Code: + width: auto +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(36:7) from "postcss-plugin" plugin: -(36:7) postcss-plugin: ", +Code: + color: white +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(41:5) from "postcss-plugin" plugin: -(41:5) postcss-plugin: ", +Code: + display: block +", "ModuleWarning: Module Warning (from \`replaced original path\`): -Warning +(6:3) from "postcss-plugin" plugin: -(6:3) postcss-plugin: ", +Code: + color: red +", ] `; @@ -214,6 +238,7 @@ exports[`loader should reuse PostCSS AST: warnings 1`] = `[]`; exports[`loader should throw an error on invalid syntax: errors 1`] = ` [ "ModuleBuildError: Module build failed (from \`replaced original path\`): + SyntaxError (1:3) /test/fixtures/css/style.css Unnecessary curly bracket