blob: 98c14be4b8b638edbf0caf3eb9d3198057cef93a [file] [log] [blame]
/* @flow */
"use strict";
const _ = require("lodash");
/*:: type messageType = {
type: string,
text: string,
line: number,
column: number,
severity: string,
rule: string,
node: Object,
index: number,
stylelintType?: string,
stylelintReference?: string,
}
*/
/*:: type postcssResultType = {
processor: {
version: string,
plugins: Array<any>,
},
messages: Array<messageType>,
root: {
raws: {
semicolon: boolean,
after: string,
},
type: string,
nodes: Array<Object>,
source: {
input: Object,
start: Object,
},
lastEach: number,
indexes: Object,
},
opts: {
from: ?string,
syntax: ?{
parse: Function,
stringify: Function,
},
},
css: string,
map: ?any,
stylelint: {
ruleSeverities: Object,
customMessages: Object,
quiet: ?any,
disabledRanges: {
all: Array<any>,
},
ignored?: boolean,
stylelintError?: boolean,
},
}
*/
/*:: type configForFileType = {
config: {
codeProcessors?: Array<Function>,
ignorePatterns?: string,
processors?: Array<any>,
quiet?: boolean,
resultProcessors?: Array<Function>,
rules: Object,
},
filepath: string,
}
*/
module.exports = function(
stylelint /*: stylelint$internalApi*/,
postcssResult /*: ?postcssResultType*/,
filePath /*: ?string*/,
cssSyntaxError /*: ?stylelint$cssSyntaxError*/
) /*: Promise<stylelint$result>*/ {
let stylelintResult;
let source;
if (postcssResult) {
source = !postcssResult.root.source
? undefined
: postcssResult.root.source.input.file ||
postcssResult.root.source.input.id;
// Strip out deprecation warnings from the messages
const deprecationMessages = _.remove(postcssResult.messages, {
stylelintType: "deprecation"
});
const deprecations = deprecationMessages.map((
deprecationMessage /*: messageType*/
) => {
return {
text: deprecationMessage.text,
reference: deprecationMessage.stylelintReference
};
});
// Also strip out invalid options
const invalidOptionMessages = _.remove(postcssResult.messages, {
stylelintType: "invalidOption"
});
const invalidOptionWarnings = invalidOptionMessages.map((
invalidOptionMessage /*: messageType*/
) => {
return {
text: invalidOptionMessage.text
};
});
const parseErrors = _.remove(postcssResult.messages, {
stylelintType: "parseError"
});
// This defines the stylelint result object that formatters receive
stylelintResult = {
source,
deprecations,
invalidOptionWarnings,
parseErrors,
errored: postcssResult.stylelint.stylelintError,
warnings: postcssResult.messages.map((message /*: messageType*/) => {
return {
line: message.line,
column: message.column,
rule: message.rule,
severity: message.severity,
text: message.text
};
}),
ignored: postcssResult.stylelint.ignored,
_postcssResult: postcssResult
};
} else if (cssSyntaxError) {
if (cssSyntaxError.name !== "CssSyntaxError") {
throw cssSyntaxError;
}
stylelintResult = {
source: cssSyntaxError.file || "<input css 1>",
deprecations: [],
invalidOptionWarnings: [],
parseErrors: [],
errored: true,
warnings: [
{
line: cssSyntaxError.line,
column: cssSyntaxError.column,
rule: cssSyntaxError.name,
severity: "error",
text: cssSyntaxError.reason + " (" + cssSyntaxError.name + ")"
}
]
};
} else {
throw new Error(
"createStylelintResult must be called with either postcssResult or CssSyntaxError"
);
}
return stylelint.getConfigForFile(filePath).then((
configForFile /*: configForFileType*/
) => {
const config = configForFile.config;
const file = source || (cssSyntaxError && cssSyntaxError.file);
if (config.resultProcessors) {
config.resultProcessors.forEach(resultProcessor => {
// Result processors might just mutate the result object,
// or might return a new one
const returned = resultProcessor(stylelintResult, file);
if (returned) {
stylelintResult = returned;
}
});
}
return stylelintResult;
});
};