Skip to content

Commit

Permalink
Merge pull request #1291 from vtex/feat/shoreline-plugins
Browse files Browse the repository at this point in the history
Shoreline Stylelint
  • Loading branch information
lucasaarcoverde authored Nov 29, 2023
2 parents 68b9fe5 + e2fb857 commit 74815f5
Show file tree
Hide file tree
Showing 17 changed files with 816 additions and 41 deletions.
25 changes: 25 additions & 0 deletions .stylelintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Keep in sync with .gitignore + .prettierignore
**/node_modules
**/dist
packages/icons/native
packages/admin-ui-docs
packages/next-docs
**/.cache
**/coverage
**/build
storybook-static
**/*.stories.ts

# Resolve: Parsing error: Unexpected token <
**/gatsby-browser.js
**/gatsby-ssr.js
**/404.js
**/src/theme/**/*.js

# Resolve: Parsing error: Unexpected token .
# not accepting conditional chaining
packages/admin-ui-codemod/src/space-tokens-review.js
packages/create-raccoon-app/src/index.js

# Resolve: Expected exception block, space or tab after '//' in comment
examples/shoreline-nextjs-integration/next-env.d.ts
9 changes: 9 additions & 0 deletions .stylelintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
extends: ['@vtex/shoreline-stylelint'],
plugins: ['stylelint-prettier'],
files: ['**/*.css'],
reportDescriptionlessDisables: true,
reportNeedlessDisables: true,
reportInvalidScopeDisables: true,
rules: {},
}
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"clean": "pnpm turbo clean && turbo run clean",
"format": "prettier --write \"packages/**/*.{ts,js,tsx,jsx,json}\" \"examples/**/*.{ts,js,tsx,jsx,json}\"",
"lint": "eslint --ext .ts,.tsx,.js,.jsx \"packages/**/*.{ts,js,tsx,jsx}\" \"examples/**/*.{ts,js,tsx,jsx}\"",
"lint:css": "stylelint '**/*.css'",
"build-storybook": "storybook build",
"dev-storybook": "pnpm storybook dev -p 6006",
"build:storybook": "pnpm build && pnpm storybook build",
Expand Down Expand Up @@ -89,7 +90,10 @@
"url-loader": "^4.1.0",
"vite": "5.0.2",
"vitest": "0.34.6",
"tsup": "8.0.1"
"tsup": "8.0.1",
"stylelint": "^15.11.0",
"stylelint-prettier": "^4.0.2",
"@vtex/shoreline-stylelint": "workspace"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
Expand Down
4 changes: 4 additions & 0 deletions packages/stylelint/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
45 changes: 45 additions & 0 deletions packages/stylelint/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Shoreline Stylelint

A configuration of [Stylelint]() rules to help with the Shoreline adoption.

## How to run?

All files:

```bash
pnpm stylelint **/*.css
```

Specific file:

```bash
pnpm run stylelint src/example.css
```

Fix:

```bash
pnpm stylelint **/*.css --fix
```

### Development

### Add new rules

1. Refer to the [Writing rules](https://stylelint.io/developer-guide/rules) guide of the Stylelint documentation

### Build custom rules

1. Refer to the [Writing plugins](https://stylelint.io/developer-guide/plugins) guide of the Stylelint documentation
2. Create your rule in the `/src/plugins` directory
3. Validate your plugin with tests (reference sibling plugins for examples)

Useful references:

1. [PostCSS API](https://postcss.org/api/): It is useful when writing a new plugin.
2. [jest-preset-stylelint](https://github.com/stylelint/jest-preset-stylelint#usage): Use this documentation when writing tests.
3. [stylelint-prettier](https://github.com/prettier/stylelint-prettier)

### Setup new rule/plugin

You must setup the new rule or plugin on [the Stylelint configuration file](./src/index.js)
40 changes: 40 additions & 0 deletions packages/stylelint/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@vtex/shoreline-stylelint",
"version": "0.0.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
},
"files": [
"dist"
],
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs",
"types": "./dist/index.d.ts"
}
},
"engines": {
"node": ">=18"
},
"scripts": {
"prebuild": "rm -rf dist",
"dev": "tsup --watch",
"build": "npm run prebuild && tsup"
},
"repository": {
"directory": "packages/stylelint",
"type": "git",
"url": "git+https://github.com/vtex/shoreline.git"
},
"bugs": {
"url": "https://github.com/vtex/shoreline/issues"
},
"peerDependencies": {
"stylelint": "^14.15.0 || ^15.0.0"
}
}
12 changes: 12 additions & 0 deletions packages/stylelint/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict'

const textPlugin = require('./plugins/no-text-property')
const spacePlugin = require('./plugins/no-px-values')

module.exports = {
plugins: [textPlugin, spacePlugin],
reportDescriptionlessDisables: true,
reportNeedlessDisables: true,
reportInvalidScopeDisables: true,
rules: { 'shoreline/no-text-property': true, 'shoreline/no-px-values': true },
}
55 changes: 55 additions & 0 deletions packages/stylelint/src/plugins/no-px-values/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# shoreline/no-px-values

Disallows use of `px` values.

```diff

// Do
+ padding: 1rem;
+ margin: 1rem 0.5rem;
// Don't
- padding: 16px;
- margin: 16px 8px;
```

## How to configure?

```js
const stylelintConfig = {
rules: {
'shoreline/no-px-values': true,
},
}
```

## How to run?

All files:

```bash
pnpm stylelint **/*.css
```

Specific file:

```bash
pnpm run stylelint src/example.css
```

## Fix

```bash
pnpm stylelint **/*.css --fix
```

```diff
- margin: 16px 8px;
+ margin: 1rem 0.5rem;
```

## Output

```bash
10:5 ✖ Expected "padding: 16px" to be "padding: 1rem". shoreline/no-px-values
11:5 ✖ Expected "margin: 8px 4px" to be "margin: 0.5rem 0.25rem". shoreline/no-px-values
```
67 changes: 67 additions & 0 deletions packages/stylelint/src/plugins/no-px-values/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const stylelint = require('stylelint')
const { replaceDeclaration } = require('../../utils/replace-declaration.js')

const { ruleMessages, validateOptions, report } = stylelint.utils

const ruleName = 'shoreline/no-px-values'
const messages = ruleMessages(ruleName, {
expected: (prop, value, expectedValue) =>
`Expected "${prop}: ${value}" to be "${prop}: ${expectedValue}".`,
})

const spaceProps = [
'margin',
'margin-left',
'margin-right',
'margin-top',
'margin-bottom',
'padding',
'padding-left',
'padding-right',
'padding-top',
'padding-bottom',
]

module.exports = stylelint.createPlugin(
ruleName,
function ruleFunction(primaryOption, secondaryOptionObject, context) {
return function lint(postcssRoot, postcssResult) {
const validOptions = validateOptions(postcssResult, ruleName, {
// No options for now...
})

if (!validOptions) return

const isAutoFixing = Boolean(context.fix)

postcssRoot.walkDecls((decl) => {
const isSpaceProp = spaceProps.includes(decl.prop)

const isInvalid = isSpaceProp && decl.value.includes('px')

if (!isInvalid) return

const pxUnits = decl.value.split('px').filter((unit) => !!unit)

const remUnits = pxUnits
.map((unit) => `${Number(unit.trim()) / 16}rem`)
.join(' ')

if (isAutoFixing) {
replaceDeclaration(decl, remUnits)
} else {
report({
ruleName,
result: postcssResult,
message: messages.expected(decl.prop, decl.value, remUnits),
node: decl,
word: 'text:',
})
}
})
}
}
)

module.exports.ruleName = ruleName
module.exports.messages = messages
66 changes: 66 additions & 0 deletions packages/stylelint/src/plugins/no-px-values/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { test, expect } from '@vtex/shoreline-test-utils'

const plugin = require('.')

const { ruleName, messages } = plugin

const stylelint = require('stylelint')

test('it allows the use of valid space values on space properties', async () => {
const code = `
margin: 1rem;
padding: 1rem 0.5rem;
padding-left: 1rem;
top: 16px;
`

const result = await stylelint.lint({
code,
config: { plugins: [plugin], rules: { [ruleName]: true } },
})

expect(result.results[0].warnings).toHaveLength(0)
})

test('it disallows the use of px values on space properties', async () => {
const code = `
margin: 16px;
`

const result = await stylelint.lint({
code,
config: {
plugins: [plugin],
rules: { [ruleName]: true },
},
})

expect(result.results[0].warnings).toHaveLength(1)

const warning = result.results[0].warnings[0]

expect(warning.rule).toBe(ruleName)
expect(warning.severity).toBe('error')
expect(warning.text).toBe(messages.expected('margin', '16px', '1rem'))
})

test('it fix the error of invalid space property value to a valid one', async () => {
const code = `
padding: 22px 8px;
`

const result = await stylelint.lint({
code,
config: {
fix: true,
plugins: [plugin],
rules: { [ruleName]: true },
},
})

expect(result.results[0].warnings).toHaveLength(0)

expect(result.output).toBe(`
padding: 1.375rem 0.5rem;
`)
})
Loading

0 comments on commit 74815f5

Please sign in to comment.