JSPM

eslint-plugin-sprinkles-lint

2.14.2
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 91
  • Score
    100M100P100Q97880F
  • License ISC

ESLint plugin for vanilla-extract sprinkles (supports both legacy and flat config)

Package Exports

  • eslint-plugin-sprinkles-lint

Readme

ESLint Plugin for Vanilla Extract Sprinkles

An ESLint plugin that warns when declaring styles without using already defined Sprinkles when using Vanilla Extract's Sprinkles feature.

ESLint Flat Config 지원 - Legacy .eslintrc 및 최신 eslint.config.js 모두 지원

Shorthands 지원 - px, py, mx, my 등 단축 속성 지원

and If you're directly using values that exist in your sprinkles config, this lint rule will automatically convert them to their corresponding sprinkles keys.

// ex

const sprinklesConfig = {
  color: {
    'gray-100': '#fafafa',
    'gray-200': '#f0f0f0',
    // .. 
  }
}

// as-is
const yourStyleAsIs = style({
  color: '#fafafa'
})

// to-be
const yourStyleToBe = sprinkles({
  color: 'gray-100'
})

Guide

if you use this plugin, i recommend this way.

STEP 1. Split your config file

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;

STEP 2. Export sprinkles.config.js to .eslintrc.sprinkles.js

  • 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",

STEP 4. Add rule to your ESLint config

Flat Config (eslint.config.js):

// eslint.config.js
const sprinklesLint = require('eslint-plugin-sprinkles-lint');

module.exports = [
  {
    files: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
    plugins: {
      "sprinkles-lint": sprinklesLint,
    },
    rules: {
      "sprinkles-lint/no-use-style-declared-sprinkles": [
        "error",
        {
          configPath: `${YOUR_CONFIG_FILE_PATH}`
        }
      ],
    },
  },
];

Legacy Config (.eslintrc.js):

// .eslintrc.js
module.exports = {
  plugins: ["sprinkles-lint"],
  rules: {
    "sprinkles-lint/no-use-style-declared-sprinkles": [
      "error",
      {
        configPath: `${YOUR_CONFIG_FILE_PATH}`
      }
    ]
  }
};

Installation

# npm
npm install eslint-plugin-sprinkles-lint

# yarn
yarn add eslint-plugin-sprinkles-lint

# pnpm
pnpm add eslint-plugin-sprinkles-lint

Usage

ESLint Flat Config (eslint.config.js) - 권장

// eslint.config.js
const sprinklesLint = require('eslint-plugin-sprinkles-lint');

module.exports = [
  {
    files: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
    plugins: {
      "sprinkles-lint": sprinklesLint,
    },
    rules: {
      "sprinkles-lint/no-use-style-declared-sprinkles": [
        "error",
        {
          configPath: './path/to/your/sprinkles.config.js'
        }
      ],
    },
  },
];

Legacy Config (.eslintrc.js)

// .eslintrc.js
module.exports = {
  plugins: ["sprinkles-lint"],
  rules: {
    "sprinkles-lint/no-use-style-declared-sprinkles": [
      "error",
      {
        configPath: './path/to/your/sprinkles.config.js'
      }
    ],
  },
};

Example

Default Setting

// 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"],
};

Case 1 - Default case (using style only)

// 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)
});

Case 2 - Using style with sprinkles in array

// 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",
  },
]);

Case 3 - Using style with sprinkles in array, but actually doesn't need style object

// 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,
});

Case 4 - Using Recipe

// 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: {
    true: sprinkles({
      cursor: "pointer",
    })
  },
});

Case 5 - Using style with sprinkles in recipe

// 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: {
    true: sprinkles({
      cursor: "pointer",
    })
  },
});

Case 6 - Using style with sprinkles in recipe, but actually doesn't need style object

// as-is
const testStyle2 = recipe({
  base: [sprinkles({
    backgroundColor: "red",
  }), {

  }],
  variants: {
    true: sprinkles({
      cursor: "pointer",
    })
  },
});
// to-be
const testStyle2 = recipe({
  // remove style object and use sprinkles only
  base: sprinkles({
    backgroundColor: "red",
  }),
  variants: {
    true: sprinkles({
      cursor: "pointer",
    })
  },
});

Case 7 - Using style value in sprinkles not key

const testStyle3 = style([
  sprinkles({
    // etc ...
  }),
  {
    color: '#fafafa' // you have '#fafafa' in sprinkles, and that is 'gray-100' (gray-100: #fafafa)
  }
])

// to-be
const testStyle3 = sprinkles({
  // etc ...
  color: 'gray-100' // auto transform and remove empty style object
})