An ESLint plugin that warns when declaring styles without using already defined Sprinkles when using Vanilla Extract's Sprinkles feature.
This Plugin does not support ESLint Flat Config yet.
Shorthands also supported.
variants in recipe is not supported. because variants must be defined only style object
if you use this plugin, i recommend this way.
i recommend you to use separated config file and using this to import in your sprinkles.css.ts
export const sprinklesProperties = {
position: ['absolute', 'relative', 'fixed', 'sticky'],
display: ['none', 'flex', 'inline-flex', 'block', 'inline', 'grid'],
flexDirection: ['row', 'column'],
justifyContent: ['stretch', 'flex-start', 'center', 'flex-end', 'space-around', 'space-between'],
alignItems: ['stretch', 'flex-start', 'center', 'flex-end', 'baseline'],
fontWeight: [500, 700],
lineHeight: ['normal', 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6]
} as const;
export const colorSprinklesProperties = {
color: theme.colors,
backgroundColor: theme.colors,
} as const;
type Shorthands = Record<string, Array<keyof typeof sprinklesProperties>>;
export const shorthands = {
p: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
px: ['paddingLeft', 'paddingRight'],
py: ['paddingTop', 'paddingBottom']
} satisfies Shorthands;
- if you don't want shorthands
// scripts/exportSprinklesConfig.js
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
async function exportConfig() {
// dynamic import for your sprinkles.config.js
const { sprinklesProperties } = await import(`${YOUR_SPRINKLES_CONFIG_PATH}`);
fs.writeFileSync(
path.resolve(__dirname, `${YOUR_CONFIG_FILE_PATH}`),
`module.exports = ${JSON.stringify(sprinklesProperties, null, 2)};`,
);
}
exportConfig().catch(console.error);
- if you want shorthands
// scripts/exportSprinklesConfig.js
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
async function exportConfig() {
const { sprinklesProperties, shorthands } = await import('../src/constants/sprinkles');
fs.writeFileSync(
path.resolve(__dirname, '../.eslintrc.sprinkles.js'),
`module.exports = {
properties: ${JSON.stringify(sprinklesProperties, null, 2)},
shorthands: ${JSON.stringify(Object.keys(shorthands), null, 2)}
};`,
);
}
exportConfig().catch(console.error);
STEP 3. Run script to export sprinkles.config.js to your .eslintrc.sprinkles.js. With tsx, you can run ESM script in Node.js
// package.json
"export-sprinkles": "tsx scripts/exportSprinklesConfig.ts",
// .eslintrc.js
"sprinkles-lint/no-use-style-declared-sprinkles": [
"error",
{
"configPath": `${YOUR_CONFIG_FILE_PATH}`
}
]
// npm
npm install eslint-plugin-sprinkles-lint
// yarn
yarn add eslint-plugin-sprinkles-lint
// pnpm
pnpm add eslint-plugin-sprinkles-lint
// .eslintrc.js
module.exports = {
plugins: ["sprinkles-lint"],
rules: {
"sprinkles-lint/no-use-style-declared-sprinkles": "error",
},
};
// sprinkles.config.js
module.exports = {
properties: {
marginTop: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
cursor: ["pointer"],
// can use array
backgroundColor: ["red", "blue", "green"],
// can use object
flex: {
1: "1 1 0%",
},
},
shorthands: ["p", "px", "py"],
};
// as-is
const testStyle = style({
backgroundColor: "red",
px: 1
});
// to-be
const testStyle = sprinkles({
backgroundColor: "red",
px: 1 // lint aware 'px' in sprinkles (by shorthands)
});
// as-is
const testStyle = style([
sprinkles({
backgroundColor: "red",
marginTop: 5,
}),
{
marginTop: 1,
display: "flex",
},
]);
// to-be
const testStyle = style([
sprinkles({
backgroundColor: "red",
marginTop: 1, // you can also remove duplicated property
}),
{
display: "flex",
},
]);
// as-is
const testStyle = style([
sprinkles({
cursor: "pointer",
}),
{
backgroundColor: "red", // already defined in sprinkles
marginTop: 1, // already defined in sprinkles
},
]);
// to-be
// remove style object and use sprinkles only
const testStyle = sprinkles({
cursor: "pointer",
backgroundColor: "red",
marginTop: 1,
});
// as-is
const testStyle = recipe({
base: {
backgroundColor: "red",
},
variants: {
cursor: "pointer"
},
});
// to-be
const testStyle = recipe({
// remove base style object and use sprinkles only
base: sprinkles({
backgroundColor: "red",
}),
variants: {
cursor: "pointer",
},
});
// as-is
const testStyle2 = recipe({
base: style([{
backgroundColor: "red",
}]),
variants: {
cursor: "pointer"
},
});
// to-be
const testStyle2 = recipe({
// remove style object and use sprinkles only
base: sprinkles({
backgroundColor: "red",
}),
variants: {
cursor: "pointer",
},
});
// as-is
const testStyle2 = recipe({
base: [sprinkles({
backgroundColor: "red",
}), {
}],
variants: {
cursor: "pointer"
},
});
// to-be
const testStyle2 = recipe({
// remove style object and use sprinkles only
base: sprinkles({
backgroundColor: "red",
}),
variants: {
cursor: "pointer",
},
});