Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1359 from IBM/527-sass-linting
feat(linting): Improve sass linting using stylelint and a custom formatter
- Loading branch information
Showing
14 changed files
with
276 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
const chalk = require('chalk'); | ||
|
||
/** | ||
* @constant | ||
*/ | ||
const ERROR = chalk.bold.red; | ||
const WARNING = chalk.yellow; | ||
const URL = chalk.underline.cyan; | ||
const NUMBER = chalk.dim; | ||
const RULE = chalk.bgWhite.black; | ||
|
||
/** | ||
* returns the boolean representing whether a file has any errors for filtering purposes | ||
* @param {Object} result - the object representing the result of a linting session | ||
* @returns {Boolean} returns true or false depending on whether the file has errors or not | ||
*/ | ||
function filterForErrors(result) { | ||
return result.errored; | ||
} | ||
|
||
/** | ||
* creates colored text that describes the severity of a problem | ||
* @param {String} severity - error.severity, the severity of the error | ||
* @returns {String} returns colored error text depending on the severity | ||
*/ | ||
function generateErrorIcon(severity) { | ||
let errorIcon = ''; | ||
switch (severity) { | ||
case 'error': | ||
errorIcon = ERROR('ERROR'); | ||
break; | ||
case 'warning': | ||
errorIcon = WARNING('warning'); | ||
break; | ||
default: | ||
errorIcon += ''; | ||
break; | ||
} | ||
return errorIcon; | ||
} | ||
|
||
/** | ||
* indents a piece of text depending on the length of the previous block of text | ||
* @param {Object} error - the specific error | ||
* @returns {String} returns the appropriate amount of tab characters | ||
*/ | ||
function formatTabbing(error) { | ||
if (`${error.line}:${error.column}`.length < 6) { | ||
return '\t \t'; | ||
} | ||
return '\t'; | ||
} | ||
|
||
/** | ||
* creates a message with a link to the carbon documentation depending on the individual error | ||
* @param {String} text - the error.text property of an error message, the defaul error message stylelint produces | ||
* @returns {String} returns a custom informational message for the type of error | ||
*/ | ||
function createCustomMessage(text) { | ||
let message = ''; | ||
if (text) { | ||
if (text.includes('color"')) { | ||
const url = URL('https://www.carbondesignsystem.com/guidelines/color/usage'); | ||
message = `\n\t${text}\n\t> Please refer to the Carbon documentation for proper color tokens: ${url}`; | ||
} else if (text.includes('"margin') || text.includes('"padding')) { | ||
const url = URL('https://www.carbondesignsystem.com/guidelines/spacing#spacing-scale'); | ||
message = `\n\t${text}\n\t> Please refer to the Carbon documentation for proper spacing values: ${url}`; | ||
} else if (text.includes('"font')) { | ||
const url = URL('https://www.carbondesignsystem.com/guidelines/typography/productive'); | ||
message = `\n\t${text}\n\t> Please refer to the Carbon productive typography documentation for proper font values: ${url}`; | ||
} else if (text.includes('transition')) { | ||
const url = URL('https://www.carbondesignsystem.com/guidelines/motion/overview'); | ||
message = `\n\t${text}\n\t> Please refer to the Carbon motion documentation for transitions: ${url}`; | ||
} | ||
} | ||
return message; | ||
} | ||
|
||
/** | ||
* formats the error message | ||
* @param {Array<object>} errors - an array of all the errors in the linting session | ||
* @returns {String} returns a formatted error message | ||
*/ | ||
|
||
function formatError(errors) { | ||
let errorMsg = ''; | ||
errors.forEach((error, i) => { | ||
const number = NUMBER(`${i + 1}.`); | ||
errorMsg += `${number} \t${generateErrorIcon(error.severity)} \t ${error.line}:${ | ||
error.column | ||
} ${formatTabbing(error)} ${RULE(error.rule)}\n \t${createCustomMessage(error.text)}\n\n`; | ||
}); | ||
|
||
return errorMsg; | ||
} | ||
|
||
/** | ||
* @type {import('stylelint').Formatter} | ||
*/ | ||
function formatter(results) { | ||
let formattedMsg = ''; | ||
if (results) { | ||
const filesWithErrors = results.filter(filterForErrors); | ||
if (filesWithErrors.length > 0) { | ||
formattedMsg += TITLE('\n!! WARNINGS !!\n\n'); | ||
} | ||
filesWithErrors.forEach(result => { | ||
const errors = result.warnings; | ||
const errorMessage = formatError(errors); | ||
formattedMsg += chalk.bold('Source: '); | ||
formattedMsg += `${result.source}\n`; | ||
formattedMsg += `${errorMessage}\n`; | ||
}); | ||
} | ||
return formattedMsg; | ||
} | ||
|
||
const formatterModule = (module.exports = formatter); | ||
formatterModule.filterForErrors = filterForErrors; | ||
formatterModule.generateErrorIcon = generateErrorIcon; | ||
formatterModule.formatTabbing = formatTabbing; | ||
formatterModule.createCustomMessage = createCustomMessage; | ||
formatterModule.formatError = formatError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
const formatter = require('./sassMsgFormatter'); | ||
const chalk = require('chalk'); | ||
|
||
const ERROR = chalk.bold.red; | ||
const WARNING = chalk.yellow; | ||
const URL = chalk.underline.cyan; | ||
const TITLE = chalk.bgYellow; | ||
|
||
const exampleOne = { | ||
source: 'test1.js', | ||
errored: true, | ||
warnings: [ | ||
{ | ||
severity: 'error', | ||
line: 21, | ||
column: 33, | ||
rule: 'declaration-property-unit-blacklist', | ||
text: 'Unexpected value in property "color"', | ||
}, | ||
], | ||
}; | ||
const exampleTwo = { | ||
source: 'test2.js', | ||
errored: true, | ||
warnings: [ | ||
{ | ||
severity: 'error', | ||
line: 123, | ||
column: 76, | ||
rule: 'declaration-property-value-blacklist', | ||
text: 'Unexpected value in "font-family"', | ||
}, | ||
], | ||
}; | ||
|
||
describe('sassMsgFormatter', () => { | ||
it('filters for errors', () => { | ||
// this function should return false unless errored is equal to true | ||
expect(formatter.filterForErrors({ errored: undefined })).toBeFalsy(); | ||
expect(formatter.filterForErrors({ errored: true })).toBeTruthy(); | ||
expect(formatter.filterForErrors({ errored: false })).toBeFalsy(); | ||
expect(formatter.filterForErrors({ errored: null })).toBeFalsy(); | ||
}); | ||
it('generates error icons', () => { | ||
// expect(generateErrorIcon('error')).toEqual(ERROR('ERROR')); | ||
expect(formatter.generateErrorIcon('error')).toContain('ERROR'); | ||
expect(formatter.generateErrorIcon('warning')).toContain('warning'); | ||
expect(formatter.generateErrorIcon(undefined)).toHaveLength(0); | ||
}); | ||
it('formats tabbing', () => { | ||
expect(formatter.formatTabbing({ line: 121, column: 23 })).toHaveLength(1); | ||
expect(formatter.formatTabbing({ line: 1, column: 123 })).toHaveLength(3); | ||
expect(formatter.formatTabbing({ line: 14, column: 23 })).toHaveLength(3); | ||
}); | ||
it('creates custom message', () => { | ||
console.log(exampleOne.warnings[0].text); | ||
expect(createCustomMessage(exampleOne.warnings[0].text)).toContain( | ||
URL('https://www.carbondesignsystem.com/guidelines/color/usage') | ||
); | ||
expect(createCustomMessage(exampleTwo.warnings[0].text)).toContain( | ||
URL('https://www.carbondesignsystem.com/guidelines/typography/productive') | ||
); | ||
expect(createCustomMessage(null)).toHaveLength(0); | ||
}); | ||
it('formats errors', () => { | ||
expect(formatter.formatError(exampleOne.warnings)).toContain(ERROR('ERROR')); | ||
expect(formatter.formatError(exampleTwo.warnings)).toContain(ERROR('ERROR')); | ||
expect( | ||
formatError([ | ||
{ | ||
severity: 'warning', | ||
line: 123, | ||
column: 45, | ||
rule: 'insert-rule-here', | ||
text: 'error text', | ||
}, | ||
]) | ||
).toContain(WARNING('warning')); | ||
}); | ||
it('formats message', () => { | ||
const resultsTest = [exampleOne, exampleTwo, { errored: false, warnings: undefined }]; | ||
expect(resultsTest.filter(formatter.filterForErrors)).toHaveLength(2); | ||
expect(formatter(resultsTest)).toContain(TITLE('\n!! WARNINGS !!\n\n')); | ||
expect(formatter(resultsTest)).toContain(formatError(exampleOne.warnings)); | ||
expect(formatter(resultsTest)).toContain(formatError(exampleTwo.warnings)); | ||
expect(formatter([{ errored: false, warnings: undefined }])).toMatch(''); | ||
expect(formatter(null)).toHaveLength(0); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,7 @@ | |
|
||
p { | ||
margin-bottom: 8px; | ||
font-size: 14px; | ||
font-size: carbon--type-scale(2); | ||
font-weight: 600; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,7 +43,7 @@ | |
svg { | ||
height: 2.5rem; | ||
width: 2.5rem; | ||
padding: 0.75rem; | ||
padding: $spacing-04; | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.