diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5f6fb98 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{ts,tsx,js,jsx,cjs,mjs,json,yaml,yml,md}] +indent_style = space +indent_size = 2 + +[*.rs] +indent_style = space +indent_size = 4 + +[Makefile] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6c7ae6..dd0ec67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,33 @@ on: - staging jobs: + format: + name: Formatting checks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Install dashboard dependencies + working-directory: dashboard + run: npm ci + + - name: Check dashboard formatting (Prettier) + working-directory: dashboard + run: npm run format:check + + - name: Install listener dependencies + working-directory: listener + run: npm ci + + - name: Check listener formatting (Prettier) + working-directory: listener + run: npm run format:check + frontend: name: Frontend (lint, typecheck, test) runs-on: ubuntu-latest diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..332bffd --- /dev/null +++ b/.prettierignore @@ -0,0 +1,26 @@ +# Dependencies +node_modules/ +dashboard/node_modules/ +listener/node_modules/ + +# Build output +dist/ +dashboard/dist/ +listener/dist/ +target/ + +# Lock files (managed by package managers, not formatted) +package-lock.json +dashboard/package-lock.json +listener/package-lock.json +Cargo.lock + +# Generated / vendored +*.wasm +*.optimized.wasm +reports/ +dashboard/reports/ + +# Environment files +.env +.env.* diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4d2523a --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/CODE_FORMATTING.md b/CODE_FORMATTING.md new file mode 100644 index 0000000..ac2edfd --- /dev/null +++ b/CODE_FORMATTING.md @@ -0,0 +1,103 @@ +# Code Formatting + +NotifyChain enforces consistent formatting across all languages via automated checks that run on every pull request. + +--- + +## Tools + +| Language | Tool | Config | +|---|---|---| +| TypeScript / TSX (dashboard) | [Prettier](https://prettier.io) 3.x | `.prettierrc` (root) | +| TypeScript (listener) | [Prettier](https://prettier.io) 3.x | `.prettierrc` (root) | +| Rust (contracts) | `rustfmt` (stable) | default `rustfmt` rules | +| All files | EditorConfig | `.editorconfig` (root) | + +--- + +## Prettier rules (TypeScript / TSX) + +Defined in `.prettierrc` at the repository root. + +| Rule | Value | +|---|---| +| `semi` | `true` — semicolons required | +| `singleQuote` | `true` — single quotes for strings | +| `trailingComma` | `"all"` — trailing commas wherever valid | +| `printWidth` | `100` — wrap lines at 100 characters | +| `tabWidth` | `2` — two-space indentation | +| `useTabs` | `false` — spaces, not tabs | +| `arrowParens` | `"always"` — parentheses around arrow function parameters | +| `endOfLine` | `"lf"` — Unix line endings | + +--- + +## Rust formatting + +The `rust` CI job runs `cargo fmt --all -- --check`. This uses the default `rustfmt` rules (stable channel). No custom `rustfmt.toml` is required. + +--- + +## EditorConfig + +`.editorconfig` enforces baseline rules in supported editors (VS Code, JetBrains, Vim, etc.) independently of any formatter: + +- UTF-8 encoding everywhere +- LF line endings everywhere +- Final newline on every file +- Trailing whitespace trimmed (except Markdown) +- 2-space indentation for TS/JS/JSON/YAML/Markdown +- 4-space indentation for Rust + +--- + +## CI enforcement + +The `format` job in `.github/workflows/ci.yml` runs on every pull request and push to `main` / `staging`: + +``` +format job + ├── dashboard: npm run format:check (Prettier --check) + └── listener: npm run format:check (Prettier --check) +``` + +The `rust` job also runs `cargo fmt --all -- --check`. + +A pull request **cannot be merged** if either check exits non-zero. + +--- + +## Fixing formatting locally + +### TypeScript / TSX + +```bash +# Fix dashboard +cd dashboard +npx prettier --write "src/**/*.{ts,tsx}" --config ../.prettierrc + +# Fix listener +cd listener +npx prettier --write "src/**/*.ts" --config ../.prettierrc +``` + +### Rust + +```bash +cd contract +cargo fmt --all +``` + +### VS Code auto-format on save + +Install the [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extension and add to `.vscode/settings.json`: + +```json +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer" + } +} +``` diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 758e0d8..14ee216 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -30,6 +30,7 @@ "jest-axe": "^10.0.0", "jest-environment-jsdom": "^29.7.0", "jsdom": "^26.1.0", + "prettier": "3.3.3", "ts-jest": "^29.2.5", "typescript": "^5.8.3", "vite": "^6.3.5" @@ -972,23 +973,6 @@ "node": ">= 6" } }, - "node_modules/@creit.tech/stellar-wallets-kit/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "extraneous": true, - "license": "Apache-2.0", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, "node_modules/@creit.tech/xbull-wallet-connect": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@creit.tech/xbull-wallet-connect/-/xbull-wallet-connect-0.4.0.tgz", @@ -7987,24 +7971,6 @@ "ws": "^7.5.1" } }, - "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "extraneous": true, - "hasInstallScript": true, - "license": "MIT", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", @@ -13130,24 +13096,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/jayson/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "extraneous": true, - "hasInstallScript": true, - "license": "MIT", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/jayson/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", @@ -16255,6 +16203,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", + "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", diff --git a/dashboard/package.json b/dashboard/package.json index b0433d9..ac5d8c7 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -8,6 +8,7 @@ "preview": "node ./node_modules/vite/bin/vite.js preview", "dev": "node ./node_modules/vite/bin/vite.js", "lint": "node ./node_modules/eslint/bin/eslint.js \"src/**/*.{ts,tsx}\" --max-warnings=0", + "format:check": "node ./node_modules/prettier/bin/prettier.cjs --check \"src/**/*.{ts,tsx}\" --config ../.prettierrc", "test": "node ./node_modules/jest/bin/jest.js", "test:wallet": "node ./node_modules/jest/bin/jest.js src/__tests__/wallet-integration.test.tsx", "benchmark": "node ./node_modules/jest/bin/jest.js src/benchmark" @@ -19,13 +20,6 @@ "zustand": "^5.0.6" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.10.0", - "@typescript-eslint/parser": "^6.10.0", - "eslint": "^8.46.0", - "eslint-plugin-react": "^7.33.0", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@types/jest": "^29.5.14", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", @@ -33,11 +27,16 @@ "@types/jest-axe": "^3.5.9", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", "@vitejs/plugin-react": "^4.7.0", + "eslint": "^8.46.0", + "eslint-plugin-react": "^7.33.0", "jest": "^29.7.0", "jest-axe": "^10.0.0", "jest-environment-jsdom": "^29.7.0", "jsdom": "^26.1.0", + "prettier": "3.3.3", "ts-jest": "^29.2.5", "typescript": "^5.8.3", "vite": "^6.3.5" diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 967b943..bb38b34 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -32,18 +32,10 @@ export function App() {
- | 'preferences'; - -export function App() { - const [tab, setTab] = useState('explorer'); - - return ( -