Skip to content

Commit 30fb521

Browse files
authored
Merge pull request #62 from NYU-ITS/feature/setup-linting-formatting
Setup Code Quality Tools (Formatting & Linting)
2 parents 5df7266 + 1d29b80 commit 30fb521

File tree

11 files changed

+3226
-251
lines changed

11 files changed

+3226
-251
lines changed

.github/workflows/code-quality.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Code Quality
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
push:
8+
branches: [main]
9+
pull_request:
10+
branches: [main]
11+
12+
jobs:
13+
code-quality:
14+
name: Code Quality
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: latest
24+
25+
- name: Install pnpm
26+
uses: pnpm/action-setup@v4
27+
28+
- name: Setup pnpm config
29+
run: |
30+
pnpm config set store-dir ~/.pnpm-store
31+
32+
- uses: actions/cache@v4
33+
name: Setup pnpm cache
34+
with:
35+
path: ~/.pnpm-store
36+
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
37+
restore-keys: |
38+
${{ runner.os }}-pnpm-store-
39+
40+
- name: Install dependencies
41+
run: pnpm install
42+
43+
- name: Check Prettier formatting
44+
run: pnpm format --check
45+
46+
- name: Run ESLint and Stylelint
47+
run: pnpm lint

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lint-staged

.prettierignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.md
2+
*.mdx
3+
4+
/pnpm-lock.yaml
5+
6+
/.github/

.vscode/extensions.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"recommendations": [
3+
"esbenp.prettier-vscode",
4+
"dbaeumer.vscode-eslint",
5+
"stylelint.vscode-stylelint"
6+
]
7+
}

eslint.config.mjs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/** @author Ka Pui (August) Cheung */
2+
3+
import path from "node:path";
4+
import { fileURLToPath } from "node:url";
5+
6+
import docusaurusPlugin from "@docusaurus/eslint-plugin";
7+
import { includeIgnoreFile } from "@eslint/compat";
8+
import eslintConfigPrettier from "eslint-config-prettier";
9+
import importPlugin from "eslint-plugin-import";
10+
import jsxA11y from "eslint-plugin-jsx-a11y";
11+
import reactPlugin from "eslint-plugin-react";
12+
import simpleImportSort from "eslint-plugin-simple-import-sort";
13+
import eslintPluginUnicorn from "eslint-plugin-unicorn";
14+
import tseslint from "typescript-eslint";
15+
16+
const __filename = fileURLToPath(import.meta.url);
17+
const __dirname = path.dirname(__filename);
18+
const gitignorePath = path.resolve(__dirname, ".gitignore");
19+
20+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
21+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
22+
/** @see https://eslint.org/docs/latest/use/configure/ */
23+
const eslintConfig = tseslint.config(
24+
includeIgnoreFile(gitignorePath),
25+
26+
// eslint-disable-next-line import/no-named-as-default-member
27+
tseslint.configs.recommendedTypeChecked,
28+
// eslint-disable-next-line import/no-named-as-default-member
29+
tseslint.configs.stylisticTypeChecked,
30+
{
31+
languageOptions: {
32+
parserOptions: {
33+
projectService: {
34+
allowDefaultProject: ["*.config.js"],
35+
},
36+
tsconfigRootDir: import.meta.dirname,
37+
},
38+
},
39+
},
40+
41+
eslintPluginUnicorn.configs.recommended,
42+
importPlugin.flatConfigs.recommended,
43+
importPlugin.flatConfigs.typescript,
44+
{
45+
settings: {
46+
"import/resolver": {
47+
typescript: true,
48+
node: true,
49+
},
50+
"import/parsers": {
51+
"@typescript-eslint/parser": [".ts", ".tsx"],
52+
},
53+
},
54+
},
55+
{
56+
plugins: {
57+
"simple-import-sort": simpleImportSort,
58+
},
59+
rules: {
60+
"simple-import-sort/imports": "warn",
61+
"simple-import-sort/exports": "warn",
62+
},
63+
},
64+
65+
reactPlugin.configs.flat.recommended,
66+
reactPlugin.configs.flat["jsx-runtime"],
67+
jsxA11y.flatConfigs.recommended,
68+
69+
{
70+
rules: {
71+
"@typescript-eslint/consistent-type-imports": [
72+
"warn",
73+
{
74+
fixStyle: "inline-type-imports",
75+
},
76+
],
77+
"@typescript-eslint/no-non-null-assertion": "error",
78+
"import/consistent-type-specifier-style": ["warn", "prefer-inline"],
79+
"import/newline-after-import": "warn",
80+
"import/no-duplicates": [
81+
"error",
82+
{
83+
"prefer-inline": true,
84+
},
85+
],
86+
"react/jsx-curly-brace-presence": ["warn", "never"],
87+
"react/jsx-sort-props": [
88+
"warn",
89+
{
90+
callbacksLast: true,
91+
multiline: "last",
92+
reservedFirst: true,
93+
shorthandFirst: true,
94+
},
95+
],
96+
"unicorn/filename-case": [
97+
"warn",
98+
{
99+
cases: {
100+
kebabCase: true,
101+
camelCase: true,
102+
pascalCase: true,
103+
},
104+
},
105+
],
106+
"unicorn/no-null": "off",
107+
"unicorn/prevent-abbreviations": [
108+
"warn",
109+
{
110+
replacements: {
111+
args: false,
112+
dev: false,
113+
env: false,
114+
params: false,
115+
props: false,
116+
ref: false,
117+
},
118+
},
119+
],
120+
},
121+
},
122+
123+
{
124+
plugins: {
125+
"@docusaurus": docusaurusPlugin,
126+
},
127+
rules: {
128+
"import/no-unresolved": [
129+
"error",
130+
{ ignore: ["^@theme", "^@docusaurus", "^@site"] },
131+
],
132+
"@docusaurus/string-literal-i18n-messages": "error",
133+
"@docusaurus/no-html-links": "warn",
134+
"@docusaurus/prefer-docusaurus-heading": "warn",
135+
},
136+
},
137+
138+
eslintConfigPrettier,
139+
);
140+
141+
export default eslintConfig;

lint-staged.config.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/** @author Ka Pui (August) Cheung */
2+
// @ts-check
3+
4+
const lintStagedConfig = {
5+
"*.{js,jsx,ts,tsx}":
6+
"eslint --fix --cache --cache-location ./node_modules/.cache/eslint",
7+
"*.{css,scss}":
8+
"stylelint --fix --cache --cache-location ./node_modules/.cache/stylelint",
9+
"*": "prettier --write --ignore-unknown --no-error-on-unmatched-pattern --cache",
10+
};
11+
12+
export default lintStagedConfig;

package.json

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,46 @@
1212
"serve": "docusaurus serve",
1313
"write-translations": "docusaurus write-translations",
1414
"write-heading-ids": "docusaurus write-heading-ids",
15-
"typecheck": "tsc"
15+
"typecheck": "tsc",
16+
"format": "prettier --write . --cache",
17+
"lint": "pnpm lint:js && pnpm lint:css",
18+
"lint:js": "eslint . --cache --cache-location ./node_modules/.cache/eslint",
19+
"lint:css": "stylelint \"src/**/*.css\" --cache --cache-location ./node_modules/.cache/stylelint",
20+
"prepare": "husky"
1621
},
1722
"dependencies": {
1823
"@docusaurus/core": "^3.7.0",
1924
"@docusaurus/preset-classic": "^3.7.0",
2025
"@mdx-js/react": "^3.1.0",
2126
"clsx": "^2.1.1",
2227
"prism-react-renderer": "^2.4.1",
23-
"react": "^18.3.1",
24-
"react-dom": "^18.3.1"
28+
"react": "^19.0.0",
29+
"react-dom": "^19.0.0"
2530
},
2631
"devDependencies": {
32+
"@docusaurus/eslint-plugin": "^3.7.0",
2733
"@docusaurus/module-type-aliases": "^3.7.0",
2834
"@docusaurus/tsconfig": "^3.7.0",
2935
"@docusaurus/types": "^3.7.0",
30-
"typescript": "~5.7.3"
36+
"@eslint/compat": "^1.2.7",
37+
"@types/react": "^19.0.10",
38+
"eslint": "^9.21.0",
39+
"eslint-config-prettier": "^10.0.1",
40+
"eslint-import-resolver-typescript": "^3.8.3",
41+
"eslint-plugin-import": "^2.31.0",
42+
"eslint-plugin-jsx-a11y": "^6.10.2",
43+
"eslint-plugin-prettier": "^5.2.3",
44+
"eslint-plugin-react": "^7.37.4",
45+
"eslint-plugin-simple-import-sort": "^12.1.1",
46+
"eslint-plugin-unicorn": "^57.0.0",
47+
"husky": "^9.1.7",
48+
"lint-staged": "^15.4.3",
49+
"prettier": "^3.5.2",
50+
"prettier-plugin-jsdoc": "^1.3.2",
51+
"stylelint": "^16.14.1",
52+
"stylelint-config-standard": "^37.0.0",
53+
"typescript": "~5.7.3",
54+
"typescript-eslint": "^8.25.0"
3155
},
3256
"browserslist": {
3357
"production": [

0 commit comments

Comments
 (0)