Skip to content

Commit 309ca9b

Browse files
feat: add stylelint-plugin (#115)
1 parent 63b3284 commit 309ca9b

File tree

23 files changed

+578
-453
lines changed

23 files changed

+578
-453
lines changed

.changeset/big-ties-melt.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@sourcegraph/eslint-plugin-sourcegraph': patch
3+
'@sourcegraph/stylelint-plugin-sourcegraph': patch
4+
'@sourcegraph/codemod-toolkit-css': patch
5+
'@sourcegraph/codemod-transforms': patch
6+
---
7+
8+
Upgraded `stylelint` version.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"format:check": "yarn format --write=false",
1717
"lint": "eslint --ignore-pattern 'demo-app' --cache .",
1818
"build": "tsc --build",
19-
"build:clean": "tsc --build --clean && rimraf ./packages/*/dist ./packages/*/*.tsbuildinfo",
19+
"build:clean": "tsc --build --clean && rimraf ./packages/*/dist ./packages/*/*.tsbuildinfo && yarn build",
2020
"build:watch": "tsc --build --watch",
2121
"postinstall": "yarn build"
2222
},
@@ -42,7 +42,7 @@
4242
"postcss-selector-parser": "^6.0.6",
4343
"prettier-eslint": "^13.0.0",
4444
"signale": "^1.4.0",
45-
"stylelint": "^13.13.1",
45+
"stylelint": "^14.3.0",
4646
"ts-morph": "14.0.0",
4747
"ts-node": "^10.1.0",
4848
"type-fest": "^2.8.0",
@@ -62,7 +62,7 @@
6262
"@types/jest": "27.0.2",
6363
"@types/node": "16.11.26",
6464
"@types/signale": "1.4.4",
65-
"@types/stylelint": "13.13.3",
65+
"@types/stylelint": "14.0.0",
6666
"eslint": "^7.32.0",
6767
"husky": "^7.0.1",
6868
"jest": "^27.0.6",

packages/eslint-plugin/jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import baseConfig from '../../jest.config.base'
44

55
const config: InitialOptionsTsJest = {
66
...baseConfig,
7-
displayName: 'codemod-eslint-plugin',
7+
displayName: 'eslint-plugin',
88
rootDir: __dirname,
99
}
1010

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# stylelint-plugin-sourcegraph
2+
3+
Recommended Stylelint rules for the Sourcegraph repo.
4+
5+
## Setup
6+
7+
Update your `.stylelintrc.json` file to add the following configuration:
8+
9+
```json
10+
{
11+
"plugins": ["@sourcegraph/stylelint-plugin-sourcegraph"],
12+
"rules": {
13+
"@sourcegraph/filenames-match-regex": [
14+
2,
15+
{
16+
"regexp": "^.+\\.module(\\.scss)$"
17+
}
18+
],
19+
"@sourcegraph/no-restricted-imports": [
20+
2,
21+
{
22+
"paths": ["bootstrap*", "reactstrap/styles.css"]
23+
}
24+
]
25+
}
26+
}
27+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */
2+
import type { InitialOptionsTsJest } from 'ts-jest'
3+
4+
import baseConfig from '../../jest.config.base'
5+
6+
const stylelintPreset = require('jest-preset-stylelint/jest-preset')
7+
const tsPreset = require('ts-jest/jest-preset')
8+
9+
const config: InitialOptionsTsJest = {
10+
...baseConfig,
11+
...tsPreset,
12+
...stylelintPreset,
13+
displayName: 'stylelint-plugin',
14+
rootDir: __dirname,
15+
setupFiles: ['./jest.setup.ts'],
16+
}
17+
18+
// eslint-disable-next-line import/no-default-export
19+
export default config
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import path from 'path'
2+
3+
import { getTestRule } from 'jest-preset-stylelint'
4+
5+
global.testRule = getTestRule({ plugins: [path.join(__dirname, './src')] })
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"name": "@sourcegraph/stylelint-plugin-sourcegraph",
3+
"version": "1.0.0",
4+
"description": "Custom stylelint rules for Sourcegraph",
5+
"keywords": [
6+
"stylelint",
7+
"stylelintplugin",
8+
"stylelint-plugin",
9+
"sourcegraph",
10+
"typescript"
11+
],
12+
"files": [
13+
"dist",
14+
"docs",
15+
"index.d.ts",
16+
"package.json",
17+
"README.md",
18+
"LICENSE"
19+
],
20+
"repository": {
21+
"type": "git",
22+
"url": "https://github.com/sourcegraph/codemod.git",
23+
"directory": "packages/stylelint-plugin"
24+
},
25+
"bugs": {
26+
"url": "https://github.com/sourcegraph/codemod/issues"
27+
},
28+
"license": "MIT",
29+
"main": "dist/index.js",
30+
"types": "index.d.ts",
31+
"scripts": {
32+
"build": "tsc --build ./tsconfig.build.json",
33+
"build:watch": "tsc --build ./tsconfig.build.json --watch",
34+
"build:clean": "tsc --build --clean ./tsconfig.build.json && rimraf dist ./*.tsbuildinfo",
35+
"typecheck": "tsc --noEmit",
36+
"test": "jest",
37+
"format": "prettier --write \"./**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
38+
"generate:configs": "ts-node --files --transpile-only scripts/generate-configs.ts",
39+
"lint": "eslint . --ext .js,.ts --ignore-path ../../.eslintignore"
40+
},
41+
"dependencies": {
42+
"@manypkg/find-root": "^1.1.0",
43+
"ignore": "^5.1.8",
44+
"postcss-value-parser": "^4.2.0"
45+
},
46+
"devDependencies": {
47+
"jest-preset-stylelint": "^5.0.3"
48+
},
49+
"peerDependencies": {
50+
"stylelint": "^14.3.0"
51+
}
52+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { filenameMatchRegexRule } from './rules/filenames-match-regex/filenames-match-regex'
2+
import { noRestrictedImports } from './rules/no-restricted-imports/no-restricted-imports'
3+
4+
// eslint-disable-next-line import/no-default-export
5+
export default [filenameMatchRegexRule, noRestrictedImports]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { messages, ruleName } from '../filenames-match-regex'
2+
3+
const ruleConfig = { regexp: '^.+\\.module(\\.css)$' }
4+
5+
testRule({
6+
ruleName,
7+
config: [true, ruleConfig],
8+
codeFilename: 'test.module.css',
9+
accept: [
10+
{
11+
code: 'div {}',
12+
description: 'CSS module file',
13+
},
14+
],
15+
})
16+
17+
testRule({
18+
ruleName,
19+
config: [true, ruleConfig],
20+
codeFilename: 'test.css',
21+
reject: [
22+
{
23+
code: 'div {}',
24+
description: 'global CSS file',
25+
message: messages.expected('test.css'),
26+
},
27+
],
28+
})
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import path from 'path'
2+
3+
import stylelint from 'stylelint'
4+
5+
import { createPlugin, isString } from '../../utils'
6+
7+
export const ruleName = '@sourcegraph/filenames-match-regex'
8+
export const messages = stylelint.utils.ruleMessages(ruleName, {
9+
expected: fileName => {
10+
return `Filename ${String(fileName)} does not match the regular expression.`
11+
},
12+
})
13+
14+
interface RuleConfig {
15+
regexp: string
16+
}
17+
18+
export const filenameMatchRegexRule = createPlugin<RuleConfig>(ruleName, (isEnabled, config) => {
19+
if (!config) {
20+
throw new Error(`The ${ruleName} rule configuration is not provided!`)
21+
}
22+
23+
const regexp = new RegExp(config.regexp)
24+
25+
return function (postcssRoot, postcssResult) {
26+
if (!isEnabled) {
27+
return
28+
}
29+
30+
const areOptionsValid = stylelint.utils.validateOptions(
31+
postcssResult,
32+
ruleName,
33+
{
34+
actual: isEnabled,
35+
optional: false,
36+
possible: [true, false],
37+
},
38+
{
39+
actual: config,
40+
optional: false,
41+
possible: {
42+
regexp: [isString],
43+
},
44+
}
45+
)
46+
47+
if (!areOptionsValid) {
48+
return
49+
}
50+
51+
const filePath = postcssRoot.source?.input.from
52+
53+
if (!filePath || !postcssRoot.first) {
54+
return
55+
}
56+
57+
const fileName = path.basename(filePath)
58+
const isRegexMatch = regexp.test(fileName)
59+
60+
if (!isRegexMatch) {
61+
stylelint.utils.report({
62+
message: messages.expected(fileName),
63+
ruleName,
64+
node: postcssRoot.first,
65+
result: postcssResult,
66+
line: 1,
67+
})
68+
}
69+
}
70+
})

0 commit comments

Comments
 (0)