README
Sketchlint
💎 Pluggable linting utility for Sketch.
Sketchlint allows you to enforce brand consistency across designs by defining a set of rules any Sketch file can be checked against.
Getting Started (CLI)
Install Sketchlint using yarn
:
yarn global add sketchlint
Then, create a file named sketchlint.config.js
. This will contain our rules:
module.exports = {
pages: {
noPagePrefix({name}) {
if (name.toLowerCase().indexOf('page') === 0) {
return ['error', `Page name contains forbidden "page" prefix.`];
}
},
},
artboards: {
noUnknownScreenSizes({frame: {width}}) {
const screenSizes = {mobile: 400, desktop: 1200};
if (!Object.values(screenSizes).includes(width)) {
return ['warning', `Width "${width}" is not a known screen size.`];
}
},
},
groups: {
maxLayers({layers}) {
const layerCount = layers.length;
if (layerCount > 10) {
return [
'warning',
`More than 10 layers in a single group can lead to confusing hierarchies.`,
];
}
},
noSpaces({name}) {
if (name.match(/\s+/)) {
return ['error', `Spaces are not allowed in group names.`];
}
},
},
meta: {
noCustomFonts({fonts}) {
const allowedFonts = ['Arial'];
for (const font of fonts) {
if (!allowedFonts.includes(font)) {
return ['error', `Font "${font}" is not a brand font.`];
}
}
},
},
layers: {
noExclamationMark({attributedString}) {
if (attributedString && attributedString.string.includes('!')) {
return ['warning', `Exclamation marks are not recommended.`];
}
},
},
document: {
noTextStyleNameSpaces({layerTextStyles: {objects: textStyles}}) {
for (const {name} of textStyles) {
if (name.match(/\s+/)) {
return [
'error',
`Spaces are not allowed in text style names ("${name}").`,
];
}
}
},
},
};
Now run Sketchlint against any (v43+) Sketch file and it will make sure it complies with your rules. Here we run Sketchlint against a Sketch file called my-design.sketch
:
sketchlint my-design.sketch --config sketchlint.config.js
page-about
error Page name contains forbidden "page" prefix. pages.noPagePrefix
meta
error Font "BrandonText-Bold" is not a brand font. meta.noCustomFonts
document
error Spaces are not allowed in text style names ("page title"). document.noTextStyleNameSpaces
homepage/v1/black box/title
warning Exclamation marks are not recommended. layers.noExclamationMark
homepage/v1/black box
warning More than 10 layers in a single group can lead to confusing hierarchies. groups.maxLayers
error Spaces are not allowed in group names. groups.noSpaces
page-about/v1
warning Width "350" is not a known screen size. artboards.noUnknownScreenSizes
✖ 7 problems (4 errors, 3 warnings)
Getting Started (Node)
Install Sketchlint using yarn
:
yarn add sketchlint
Now run Sketchlint against any (v43+) Sketch file and it will check if the file complies with the given set of rules and give back an array of linting errors (if there are any).
import fs from 'fs';
import sketchlint from 'sketchlint';
const sketchData = fs.readFileSync(`${__dirname}/fixtures/basic.sketch`);
const lintingErrors = await sketchlint(sketchData, {
pages: {
noPagePrefix({name}) {
if (name.toLowerCase().indexOf('page') === 0) {
return ['error', `Page name contains forbidden "page" prefix.`];
}
},
},
artboards: {
noUnknownScreenSizes({frame: {width}}) {
const screenSizes = {mobile: 400, desktop: 1200};
if (!Object.values(screenSizes).includes(width)) {
return ['warning', `Width "${width}" is not a known screen size.`];
}
},
},
groups: {
maxLayers({layers}) {
const layerCount = layers.length;
if (layerCount > 10) {
return [
'warning',
`More than 10 layers in a single group can lead to confusing hierarchies.`,
];
}
},
noSpaces({name}) {
if (name.match(/\s+/)) {
return ['error', `Spaces are not allowed in group names.`];
}
},
},
meta: {
noCustomFonts({fonts}) {
const allowedFonts = ['Arial'];
for (const font of fonts) {
if (!allowedFonts.includes(font)) {
return ['error', `Font "${font}" is not a brand font.`];
}
}
},
},
layers: {
noExclamationMark({attributedString}) {
if (attributedString && attributedString.string.includes('!')) {
return ['warning', `Exclamation marks are not recommended.`];
}
},
},
document: {
noTextStyleNameSpaces({layerTextStyles: {objects: textStyles}}) {
for (const {name} of textStyles) {
if (name.match(/\s+/)) {
return [
'error',
`Spaces are not allowed in text style names ("${name}").`,
];
}
}
},
},
});
console.log(lintingErrors);
🏗 Contributing
- Make your changes.
- Add/Alter the appropriate tests.
- Make sure all tests pass (
yarn lint && yarn test
). - Create a PR.