From 69cbcad355bb3a882ad364f92b61a2f6d1c76acd Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Fri, 8 Sep 2023 15:26:29 +0000 Subject: [PATCH 1/3] feat: Implement griffel stylelint config Implements a stylelint config for griffel that uses the postcss syntax. Also adds tests for stylelint integration. --- packages/postcss-syntax/package.json | 3 +- packages/postcss-syntax/src/createSyntax.ts | 2 +- packages/postcss-syntax/src/parse.ts | 10 ++- packages/postcss-syntax/src/stringify.ts | 1 - packages/stylelint-config/.babelrc | 3 + packages/stylelint-config/.eslintrc.json | 18 +++++ packages/stylelint-config/README.md | 45 +++++++++++ packages/stylelint-config/jest.config.ts | 16 ++++ packages/stylelint-config/package.json | 13 +++ packages/stylelint-config/project.json | 55 +++++++++++++ packages/stylelint-config/src/index.ts | 5 ++ .../stylelint-config/src/stylelint.test.ts | 81 +++++++++++++++++++ packages/stylelint-config/tsconfig.json | 22 +++++ packages/stylelint-config/tsconfig.lib.json | 11 +++ packages/stylelint-config/tsconfig.spec.json | 20 +++++ tsconfig.base.json | 1 + workspace.json | 1 + 17 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 packages/stylelint-config/.babelrc create mode 100644 packages/stylelint-config/.eslintrc.json create mode 100644 packages/stylelint-config/README.md create mode 100644 packages/stylelint-config/jest.config.ts create mode 100644 packages/stylelint-config/package.json create mode 100644 packages/stylelint-config/project.json create mode 100644 packages/stylelint-config/src/index.ts create mode 100644 packages/stylelint-config/src/stylelint.test.ts create mode 100644 packages/stylelint-config/tsconfig.json create mode 100644 packages/stylelint-config/tsconfig.lib.json create mode 100644 packages/stylelint-config/tsconfig.spec.json diff --git a/packages/postcss-syntax/package.json b/packages/postcss-syntax/package.json index 9e091fd532..5a44425ddd 100644 --- a/packages/postcss-syntax/package.json +++ b/packages/postcss-syntax/package.json @@ -12,6 +12,5 @@ "@griffel/babel-preset": "^1.5.0", "@babel/helper-plugin-utils": "^7.12.13", "postcss": "^8.4.29" - }, - "main": "index.js" + } } diff --git a/packages/postcss-syntax/src/createSyntax.ts b/packages/postcss-syntax/src/createSyntax.ts index 8796c54839..543cf252bc 100644 --- a/packages/postcss-syntax/src/createSyntax.ts +++ b/packages/postcss-syntax/src/createSyntax.ts @@ -9,7 +9,7 @@ import { BabelPluginOptions } from '@griffel/babel-preset'; * @returns a postcss custom syntax */ export function createSyntax(options: BabelPluginOptions): postcss.Syntax { - const extendedParse: postcss.Parser = (css, opts) => parse(css, { ...opts, ...options }); + const extendedParse: postcss.Parser = (css, opts) => parse(css, { ...opts, griffelPreset: { ...options } }); return { stringify, diff --git a/packages/postcss-syntax/src/parse.ts b/packages/postcss-syntax/src/parse.ts index d32f8600ed..d05678b989 100644 --- a/packages/postcss-syntax/src/parse.ts +++ b/packages/postcss-syntax/src/parse.ts @@ -5,16 +5,18 @@ import { BabelPluginOptions } from '@griffel/babel-preset'; export type PostCSSParserOptions = Pick, 'from' | 'map'>; -export interface ParserOptions extends PostCSSParserOptions, BabelPluginOptions {} +export interface ParserOptions extends PostCSSParserOptions { + griffelPreset?: BabelPluginOptions; +} export const parse = (css: string | { toString(): string }, opts?: ParserOptions) => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { from: filename = 'postcss-syntax.styles.ts', map, ...griffelPluginOptions } = opts ?? {}; + const { from: filename = 'postcss-syntax.styles.ts', griffelPreset } = opts ?? {}; + const code = css.toString(); const { metadata } = transformSync(code, { filename, pluginOptions: { - ...griffelPluginOptions, + ...griffelPreset, generateMetadata: true, }, }); diff --git a/packages/postcss-syntax/src/stringify.ts b/packages/postcss-syntax/src/stringify.ts index 19301064b4..fbbfd40fbd 100644 --- a/packages/postcss-syntax/src/stringify.ts +++ b/packages/postcss-syntax/src/stringify.ts @@ -4,7 +4,6 @@ import { GRIFFEL_SRC_RAW } from './constants'; export const stringify: postcss.Stringifier = root => { const originalSource = root.raw(GRIFFEL_SRC_RAW); if (originalSource) { - console.log(originalSource); return originalSource; } diff --git a/packages/stylelint-config/.babelrc b/packages/stylelint-config/.babelrc new file mode 100644 index 0000000000..cf7ddd99c6 --- /dev/null +++ b/packages/stylelint-config/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] +} diff --git a/packages/stylelint-config/.eslintrc.json b/packages/stylelint-config/.eslintrc.json new file mode 100644 index 0000000000..9d9c0db55b --- /dev/null +++ b/packages/stylelint-config/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/packages/stylelint-config/README.md b/packages/stylelint-config/README.md new file mode 100644 index 0000000000..3750e1794e --- /dev/null +++ b/packages/stylelint-config/README.md @@ -0,0 +1,45 @@ +# Standard Stylelint config for Griffel + +This is a a standard [stylelint](https://stylelint.io/) that can be used to lint Griffel CSS in JS. +It uses the [Griffel postcss syntax](https://github.com/microsoft/griffel/tree/main/packages/postcss-syntax) as +a base config for any stylelint integration. + +## Usage + +Simply extend this configuration in your stylelint config + +```json +{ + "extends": "@griffe/stylelint-config", + "rules": { + "alpha-value-notation": "number" + } +} +``` + +## Different module source or imports + +If you are using a different module source or import name like the below example: + +```ts +import { foo /* makeStyles */ } from '@foo/foo'; /* @griffel/react */ + +export const useStyles = foo({ + root: { + color: 'red', + }, +}); +``` + +There is no way to customize postcss custom syntaxes, so the only way to make linting these CSS in JS files +possible is to create the griffel postcss custom syntax from a factory that can be configured. For this to work +you'll need to use a javascript stylelint config `.stylelintrc.js` + +```js +module.exports { + customSyntax: require('@griffel/postcss-syntax').createSyntax({ modules: [{ moduleSource: '@foo/foo', importName: 'foo' }] }), + rules: { + "alpha-value-notation": "number" + } +} +``` diff --git a/packages/stylelint-config/jest.config.ts b/packages/stylelint-config/jest.config.ts new file mode 100644 index 0000000000..78fa36099b --- /dev/null +++ b/packages/stylelint-config/jest.config.ts @@ -0,0 +1,16 @@ +/* eslint-disable */ +export default { + displayName: 'eslint-plugin', + preset: '../../jest.preset.js', + globals: { + 'ts-jest': { + tsconfig: '/tsconfig.spec.json', + }, + }, + testEnvironment: 'node', + transform: { + '^.+\\.[tj]sx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], + coverageDirectory: '../../coverage/packages/eslint-plugin', +}; diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json new file mode 100644 index 0000000000..7b737364ef --- /dev/null +++ b/packages/stylelint-config/package.json @@ -0,0 +1,13 @@ +{ + "name": "@griffel/stylelint-config", + "version": "0.0.0", + "description": "A default stylelint config for Griffel", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/griffel" + }, + "dependencies": { + "@griffel/postcss-syntax": "^1.0.0" + } +} diff --git a/packages/stylelint-config/project.json b/packages/stylelint-config/project.json new file mode 100644 index 0000000000..79297605ef --- /dev/null +++ b/packages/stylelint-config/project.json @@ -0,0 +1,55 @@ +{ + "name": "@griffel/stylelint-config", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/stylelint-config/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["packages/stylelint-config/**/*.ts"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["{workspaceRoot}/coverage/packages/stylelint-config"], + "options": { + "jestConfig": "packages/stylelint-config/jest.config.ts", + "passWithNoTests": true + } + }, + "build": { + "executor": "@nrwl/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/packages/stylelint-config", + "tsConfig": "packages/stylelint-config/tsconfig.lib.json", + "packageJson": "packages/stylelint-config/package.json", + "main": "packages/stylelint-config/src/index.ts", + "updateBuildableProjectDepsInPackageJson": false, + "assets": [ + "packages/stylelint-config/README.md", + { + "glob": "LICENSE.md", + "input": ".", + "output": "." + } + ] + } + }, + "type-check": { + "executor": "nx:run-commands", + "options": { + "cwd": "packages/babel-preset", + "commands": [ + { + "command": "tsc -b --pretty" + } + ], + "outputPath": [] + } + } + }, + "tags": [] +} diff --git a/packages/stylelint-config/src/index.ts b/packages/stylelint-config/src/index.ts new file mode 100644 index 0000000000..cccc28f995 --- /dev/null +++ b/packages/stylelint-config/src/index.ts @@ -0,0 +1,5 @@ +import griffelSyntax from '@griffel/postcss-syntax'; + +export default { + customSyntax: griffelSyntax, +}; diff --git a/packages/stylelint-config/src/stylelint.test.ts b/packages/stylelint-config/src/stylelint.test.ts new file mode 100644 index 0000000000..b719edc5d9 --- /dev/null +++ b/packages/stylelint-config/src/stylelint.test.ts @@ -0,0 +1,81 @@ +import * as stylelint from 'stylelint'; +import griffelStylelintConfig from './index'; +import { createSyntax } from '@griffel/postcss-syntax'; + +describe('stylelint', () => { + it('should lint makeStyles with standard config', async () => { + expect.assertions(1); + const config = { + ...griffelStylelintConfig, + rules: { + 'selector-anb-no-unmatchable': [true], + }, + }; + + const code = ` +import { makeStyles } from '@griffel/react'; + +const useStyles = makeStyles({ + root: { + ':nth-child(0)': { + color: 'red', + } + } +}) +`; + + const { results } = await stylelint.lint({ code, config }); + const warnings = results.map(result => result.warnings).flat(); + expect(warnings).toMatchInlineSnapshot(` + Array [ + Object { + "column": 11, + "endColumn": 24, + "endLine": 5, + "line": 5, + "rule": "selector-anb-no-unmatchable", + "severity": "error", + "text": "Unexpected unmatchable An+B selector \\":nth-child\\" (selector-anb-no-unmatchable)", + }, + ] + `); + }); + + it('should lint makeStyles with different module source', async () => { + expect.assertions(1); + const config = { + customSyntax: createSyntax({ modules: [{ moduleSource: '@foo/foo', importName: 'foo' }] }), + rules: { + 'selector-anb-no-unmatchable': [true], + }, + }; + + const code = ` +import { foo } from '@foo/foo'; + +const useStyles = foo({ + root: { + ':nth-child(0)': { + color: 'red', + } + } +}) +`; + + const { results } = await stylelint.lint({ code, config }); + const warnings = results.map(result => result.warnings).flat(); + expect(warnings).toMatchInlineSnapshot(` + Array [ + Object { + "column": 11, + "endColumn": 24, + "endLine": 5, + "line": 5, + "rule": "selector-anb-no-unmatchable", + "severity": "error", + "text": "Unexpected unmatchable An+B selector \\":nth-child\\" (selector-anb-no-unmatchable)", + }, + ] + `); + }); +}); diff --git a/packages/stylelint-config/tsconfig.json b/packages/stylelint-config/tsconfig.json new file mode 100644 index 0000000000..e464c9eb82 --- /dev/null +++ b/packages/stylelint-config/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "allowJs": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/stylelint-config/tsconfig.lib.json b/packages/stylelint-config/tsconfig.lib.json new file mode 100644 index 0000000000..0a5aff6efc --- /dev/null +++ b/packages/stylelint-config/tsconfig.lib.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node", "environment"] + }, + "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"], + "include": ["**/*.ts"] +} diff --git a/packages/stylelint-config/tsconfig.spec.json b/packages/stylelint-config/tsconfig.spec.json new file mode 100644 index 0000000000..bc9c667a00 --- /dev/null +++ b/packages/stylelint-config/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node", "environment"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.test.tsx", + "**/*.spec.tsx", + "**/*.test.js", + "**/*.spec.js", + "**/*.test.jsx", + "**/*.spec.jsx", + "**/*.d.ts", + "jest.config.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 3f9920744b..b8a3d24df0 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -23,6 +23,7 @@ "@griffel/jest-serializer": ["packages/jest-serializer/src/index.ts"], "@griffel/next-extraction-plugin": ["packages/next-extraction-plugin/src/index.ts"], "@griffel/postcss-syntax": ["packages/postcss-syntax/src/index.ts"], + "@griffel/stylelint-config": ["packages/stylelint-config/src/index.ts"], "@griffel/style-types": ["packages/style-types/src/index.ts"], "@griffel/react": ["packages/react/src/index.ts"], "@griffel/webpack-extraction-plugin": ["packages/webpack-extraction-plugin/src/index.ts"], diff --git a/workspace.json b/workspace.json index d8ebbb4ff3..cf14c0dd69 100644 --- a/workspace.json +++ b/workspace.json @@ -13,6 +13,7 @@ "@griffel/next-extraction-plugin": "packages/next-extraction-plugin", "@griffel/postcss-syntax": "packages/postcss-syntax", "@griffel/react": "packages/react", + "@griffel/stylelint-config": "packages/stylelint-config", "@griffel/style-types": "packages/style-types", "@griffel/webpack-extraction-plugin": "packages/webpack-extraction-plugin", "@griffel/webpack-loader": "packages/webpack-loader", From 6c2288765804beb843a4f0c47b0efde77935759c Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Fri, 8 Sep 2023 15:27:50 +0000 Subject: [PATCH 2/3] Change files --- ...ostcss-syntax-7bdb7ebd-9801-493e-b0d9-6c4ec1ed1e51.json | 7 +++++++ ...lelint-config-d9211c16-0901-4a98-9823-d565b4aee144.json | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 change/@griffel-postcss-syntax-7bdb7ebd-9801-493e-b0d9-6c4ec1ed1e51.json create mode 100644 change/@griffel-stylelint-config-d9211c16-0901-4a98-9823-d565b4aee144.json diff --git a/change/@griffel-postcss-syntax-7bdb7ebd-9801-493e-b0d9-6c4ec1ed1e51.json b/change/@griffel-postcss-syntax-7bdb7ebd-9801-493e-b0d9-6c4ec1ed1e51.json new file mode 100644 index 0000000000..70c82b4f5e --- /dev/null +++ b/change/@griffel-postcss-syntax-7bdb7ebd-9801-493e-b0d9-6c4ec1ed1e51.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: entrypoint and preset config fixes", + "packageName": "@griffel/postcss-syntax", + "email": "lingfan.gao@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@griffel-stylelint-config-d9211c16-0901-4a98-9823-d565b4aee144.json b/change/@griffel-stylelint-config-d9211c16-0901-4a98-9823-d565b4aee144.json new file mode 100644 index 0000000000..22da1ce800 --- /dev/null +++ b/change/@griffel-stylelint-config-d9211c16-0901-4a98-9823-d565b4aee144.json @@ -0,0 +1,7 @@ +{ + "type": "major", + "comment": "Initial release", + "packageName": "@griffel/stylelint-config", + "email": "lingfan.gao@microsoft.com", + "dependentChangeType": "patch" +} From 462fcd4e60aca2c786ed96a49e8674193df5ffe8 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Fri, 8 Sep 2023 15:34:02 +0000 Subject: [PATCH 3/3] fix tests --- packages/postcss-syntax/src/parse.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/postcss-syntax/src/parse.test.ts b/packages/postcss-syntax/src/parse.test.ts index 837bfb0695..bf994e0c63 100644 --- a/packages/postcss-syntax/src/parse.test.ts +++ b/packages/postcss-syntax/src/parse.test.ts @@ -57,7 +57,9 @@ export const useStyles = foo({ `; const root = parse(fixture, { from: 'fixture.styles.ts', - modules: [{ moduleSource: '@foo/foo', importName: 'foo' }], + griffelPreset: { + modules: [{ moduleSource: '@foo/foo', importName: 'foo' }], + }, }); expect(format(root.toString())).toMatchInlineSnapshot(` ".fe3e8s9 { @@ -203,7 +205,9 @@ export const useResetStyles = foo({ `; const root = parse(fixture, { from: 'fixture.styles.ts', - modules: [{ moduleSource: '@foo/foo', importName: 'makeStyles', resetImportName: 'foo' }], + griffelPreset: { + modules: [{ moduleSource: '@foo/foo', importName: 'makeStyles', resetImportName: 'foo' }], + }, }); expect(format(root.toString())).toMatchInlineSnapshot(` ".rbe9p1m {