From cb582dc601a041cd278d42ee7b68461e9b9b2b06 Mon Sep 17 00:00:00 2001 From: Saumil Patel Date: Fri, 6 Mar 2026 22:34:58 +0200 Subject: [PATCH 1/3] Modernize github pages site --- .github/workflows/pages.yml | 150 +- .gitignore | 3 + README.md | 2 +- site/index.html | 20 + site/package-lock.json | 3062 +++++++++++ site/package.json | 32 + site/postcss.config.js | 6 + site/public/404.html | 18 + site/public/favicon.svg | 27 + site/public/logo-full.svg | 17 + site/public/logo-mark.svg | 17 + site/public/robots.txt | 3 + site/public/sitemap.xml | 54 + site/public/social-card.png | Bin 0 -> 36500 bytes site/scripts/build-pattern-index.mjs | 110 + site/scripts/build-related-patterns.mjs | 61 + site/scripts/extract-pattern-metadata.mjs | 260 + site/scripts/markdown-utils.mjs | 144 + site/src/App.tsx | 221 + site/src/components/common/Button.tsx | 38 + .../components/filters/CategoryFilterBar.tsx | 39 + site/src/components/layout/AppShell.tsx | 25 + site/src/components/layout/Footer.tsx | 25 + site/src/components/layout/Header.tsx | 110 + .../src/components/patterns/CategoryBadge.tsx | 10 + site/src/components/patterns/PatternCard.tsx | 51 + .../components/patterns/RelatedPatterns.tsx | 26 + .../src/components/search/HighlightedText.tsx | 26 + site/src/components/search/SearchBar.tsx | 31 + .../search/SearchCommandPalette.tsx | 173 + site/src/components/search/SearchResults.tsx | 44 + site/src/content/patterns.json | 4784 +++++++++++++++++ site/src/content/related-patterns.json | 260 + site/src/data/categories.ts | 63 + site/src/lib/github.ts | 3 + site/src/lib/markdown.ts | 11 + site/src/lib/search.ts | 158 + site/src/lib/seo.ts | 47 + site/src/main.tsx | 20 + site/src/pages/AboutPage.tsx | 31 + site/src/pages/CatalogPage.tsx | 87 + site/src/pages/HomePage.tsx | 132 + site/src/pages/NotFoundPage.tsx | 24 + site/src/pages/PatternPage.tsx | 140 + site/src/styles/index.css | 40 + site/src/styles/prose.css | 72 + site/src/types/pattern.ts | 37 + site/tailwind.config.ts | 19 + site/tsconfig.json | 21 + site/vite.config.ts | 11 + 50 files changed, 10634 insertions(+), 131 deletions(-) create mode 100644 site/index.html create mode 100644 site/package-lock.json create mode 100644 site/package.json create mode 100644 site/postcss.config.js create mode 100644 site/public/404.html create mode 100644 site/public/favicon.svg create mode 100644 site/public/logo-full.svg create mode 100644 site/public/logo-mark.svg create mode 100644 site/public/robots.txt create mode 100644 site/public/sitemap.xml create mode 100644 site/public/social-card.png create mode 100644 site/scripts/build-pattern-index.mjs create mode 100644 site/scripts/build-related-patterns.mjs create mode 100644 site/scripts/extract-pattern-metadata.mjs create mode 100644 site/scripts/markdown-utils.mjs create mode 100644 site/src/App.tsx create mode 100644 site/src/components/common/Button.tsx create mode 100644 site/src/components/filters/CategoryFilterBar.tsx create mode 100644 site/src/components/layout/AppShell.tsx create mode 100644 site/src/components/layout/Footer.tsx create mode 100644 site/src/components/layout/Header.tsx create mode 100644 site/src/components/patterns/CategoryBadge.tsx create mode 100644 site/src/components/patterns/PatternCard.tsx create mode 100644 site/src/components/patterns/RelatedPatterns.tsx create mode 100644 site/src/components/search/HighlightedText.tsx create mode 100644 site/src/components/search/SearchBar.tsx create mode 100644 site/src/components/search/SearchCommandPalette.tsx create mode 100644 site/src/components/search/SearchResults.tsx create mode 100644 site/src/content/patterns.json create mode 100644 site/src/content/related-patterns.json create mode 100644 site/src/data/categories.ts create mode 100644 site/src/lib/github.ts create mode 100644 site/src/lib/markdown.ts create mode 100644 site/src/lib/search.ts create mode 100644 site/src/lib/seo.ts create mode 100644 site/src/main.tsx create mode 100644 site/src/pages/AboutPage.tsx create mode 100644 site/src/pages/CatalogPage.tsx create mode 100644 site/src/pages/HomePage.tsx create mode 100644 site/src/pages/NotFoundPage.tsx create mode 100644 site/src/pages/PatternPage.tsx create mode 100644 site/src/styles/index.css create mode 100644 site/src/styles/prose.css create mode 100644 site/src/types/pattern.ts create mode 100644 site/tailwind.config.ts create mode 100644 site/tsconfig.json create mode 100644 site/vite.config.ts diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 6a2a24f..96effb1 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,8 +1,8 @@ -name: Build HTML and Deploy Pages +name: Deploy modern site to GitHub Pages on: push: - branches: [ "main", "master" ] + branches: ["main"] workflow_dispatch: permissions: @@ -11,152 +11,42 @@ permissions: id-token: write concurrency: - group: pages + group: "pages" cancel-in-progress: true jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - name: Checkout source + - name: Checkout uses: actions/checkout@v4 - - name: Install Pandoc + Chromium deps - run: | - sudo apt-get update - sudo apt-get install -y \ - pandoc \ - librsvg2-bin \ - libgbm1 \ - libnss3 \ - libatk1.0-0 \ - libatk-bridge2.0-0 \ - libcups2 \ - libxcomposite1 \ - libxdamage1 \ - libxrandr2 \ - libxss1 \ - libxtst6 \ - fonts-liberation \ - ca-certificates \ - lsb-release \ - xdg-utils - sudo apt-get install -y libasound2 || sudo apt-get install -y libasound2t64 - - - name: Verify rsvg-convert - run: | - command -v rsvg-convert && rsvg-convert --version || echo "rsvg-convert not found" - - - name: Setup Node.js + - name: Setup Node uses: actions/setup-node@v4 with: - node-version: "20" - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install Mermaid CLI - run: | - npm install -g @mermaid-js/mermaid-cli - - - name: Mermaid smoke test (Chromium/Puppeteer) - run: | - mkdir -p book-output/diagrams - cat > book-output/diagrams/smoke.mmd <<'MMD' - sequenceDiagram - participant A - participant B - A->>B: hello - MMD - cat > book-output/diagrams/puppeteer-smoke.json <<'JSON' - { "args": ["--no-sandbox", "--disable-setuid-sandbox"] } - JSON - mmdc \ - -i book-output/diagrams/smoke.mmd \ - -o book-output/diagrams/smoke.png \ - --backgroundColor "#ffffff" \ - --puppeteerConfigFile book-output/diagrams/puppeteer-smoke.json - - - name: Generate master markdown - run: | - mkdir -p book-output - { - printf '%s\n' '---' - printf '%s\n' 'title: "Design Patterns in Java"' - printf '%s\n' 'subtitle: "Practical, Runnable Examples"' - printf 'date: "%s"\n' "$(date -u +'%Y-%m-%d %H:%M UTC')" - printf '%s\n' 'lang: en' - printf '%s\n\n' '---' - } > book-output/design-patterns-book.md - - if [ -f "README.md" ]; then - echo "---" >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - cat README.md >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - fi - - categories=( \ - gof-patterns \ - enterprise-integration-patterns \ - reliability-patterns \ - architectural-patterns \ - miscellaneous-patterns \ - ) - - for category in "${categories[@]}"; do - if [ -f "$category/README.md" ]; then - echo "---" >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - cat "$category/README.md" >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - fi - - for pattern_dir in $(ls -d "$category"/*/ 2>/dev/null | sort); do - if [ -f "$pattern_dir/README.md" ]; then - echo "---" >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - cat "$pattern_dir/README.md" >> book-output/design-patterns-book.md - echo "" >> book-output/design-patterns-book.md - fi - done - done + node-version: 22 + cache: npm + cache-dependency-path: site/package-lock.json - - name: Render Mermaid diagrams - run: | - mkdir -p book-output/diagrams - python3 scripts/render_mermaid.py \ - book-output/design-patterns-book.md \ - book-output/design-patterns-book.with-diagrams.md \ - book-output/diagrams + - name: Install dependencies + working-directory: site + run: npm ci - - name: Build HTML - run: | - mkdir -p book-output/html - pandoc book-output/design-patterns-book.with-diagrams.md \ - -o book-output/html/index.html \ - --standalone \ - --css=https://cdn.jsdelivr.net/npm/water.css@2/out/water.css \ - --resource-path=.:book-output \ - --table-of-contents \ - --toc-depth=3 \ - --number-sections \ - --highlight-style=pygments + - name: Generate pattern index + working-directory: site + run: npm run build:content - - name: Copy diagrams into HTML output - run: | - mkdir -p book-output/html/diagrams - cp book-output/diagrams/*.png book-output/html/diagrams/ || true + - name: Build site + working-directory: site + run: npm run build - name: Setup Pages uses: actions/configure-pages@v5 - - name: Upload artifact to GitHub Pages + - name: Upload Pages artifact uses: actions/upload-pages-artifact@v3 with: - path: book-output/html + path: site/dist deploy: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 3fa9ad8..38a9c9b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ target *.uml .idea/ .vscode/ +site/node_modules/ +site/dist/ +book-output/ diff --git a/README.md b/README.md index 6ad043d..58e2188 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![CI](https://github.com/SaumilP/design-patterns/actions/workflows/ci.yml/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -![Java](https://img.shields.io/badge/Java-11%2B-orange) +![Java](https://img.shields.io/badge/Java-21%2B-orange) [![Pages](https://img.shields.io/badge/Github-Pages-green)](https://saumilp.github.io/design-patterns) ![GitHub Repo stars](https://img.shields.io/github/stars/saumilp/design-patterns) diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..e5450ac --- /dev/null +++ b/site/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + Design Patterns | Practical Java examples + + +
+ + + diff --git a/site/package-lock.json b/site/package-lock.json new file mode 100644 index 0000000..e410e38 --- /dev/null +++ b/site/package-lock.json @@ -0,0 +1,3062 @@ +{ + "name": "design-patterns-site", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "design-patterns-site", + "version": "0.1.0", + "dependencies": { + "flexsearch": "^0.8.212", + "gray-matter": "^4.0.3", + "markdown-it": "^14.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.3.0" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@types/node": "^24.0.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^5.0.0", + "autoprefixer": "^10.4.21", + "postcss": "^8.5.3", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.2", + "vite": "^7.1.3" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", + "integrity": "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", + "integrity": "sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001774", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flexsearch": { + "version": "0.8.212", + "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.8.212.tgz", + "integrity": "sha512-wSyJr1GUWoOOIISRu+X2IXiOcVfg9qqBRyCPRUdLMIGJqPzMo+jMRlvE83t14v1j0dRMEaBbER/adQjp6Du2pw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/ts-thomas" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/donate/?hosted_button_id=GEVR88FC9BWRW" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/flexsearch" + }, + { + "type": "patreon", + "url": "https://patreon.com/user?u=96245532" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/ts-thomas" + } + ], + "license": "Apache-2.0" + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz", + "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz", + "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/site/package.json b/site/package.json new file mode 100644 index 0000000..fee67e0 --- /dev/null +++ b/site/package.json @@ -0,0 +1,32 @@ +{ + "name": "design-patterns-site", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "npm run build:content && vite", + "build:content": "node scripts/build-pattern-index.mjs && node scripts/build-related-patterns.mjs", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "flexsearch": "^0.8.212", + "gray-matter": "^4.0.3", + "markdown-it": "^14.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-router-dom": "^7.3.0" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16", + "@types/node": "^24.0.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^5.0.0", + "autoprefixer": "^10.4.21", + "postcss": "^8.5.3", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.2", + "vite": "^7.1.3" + } +} diff --git a/site/postcss.config.js b/site/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/site/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/site/public/404.html b/site/public/404.html new file mode 100644 index 0000000..b31cbcd --- /dev/null +++ b/site/public/404.html @@ -0,0 +1,18 @@ + + + + + + + Redirecting… + + + diff --git a/site/public/favicon.svg b/site/public/favicon.svg new file mode 100644 index 0000000..f548c90 --- /dev/null +++ b/site/public/favicon.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + +*** Add File: site/public/logo-icon.svg + + + + + + + + + + + + + diff --git a/site/public/logo-full.svg b/site/public/logo-full.svg new file mode 100644 index 0000000..5fd1cc0 --- /dev/null +++ b/site/public/logo-full.svg @@ -0,0 +1,17 @@ + + + + + + + + Pattern Hex + practical java design patterns + + + + + + + + diff --git a/site/public/logo-mark.svg b/site/public/logo-mark.svg new file mode 100644 index 0000000..5fd1cc0 --- /dev/null +++ b/site/public/logo-mark.svg @@ -0,0 +1,17 @@ + + + + + + + + Pattern Hex + practical java design patterns + + + + + + + + diff --git a/site/public/robots.txt b/site/public/robots.txt new file mode 100644 index 0000000..0cd237a --- /dev/null +++ b/site/public/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://saumilp.github.io/design-patterns/sitemap.xml diff --git a/site/public/sitemap.xml b/site/public/sitemap.xml new file mode 100644 index 0000000..d1020ad --- /dev/null +++ b/site/public/sitemap.xml @@ -0,0 +1,54 @@ + + + https://saumilp.github.io/design-patterns/ + https://saumilp.github.io/design-patterns/patterns + https://saumilp.github.io/design-patterns/about + https://saumilp.github.io/design-patterns/categories/gof + https://saumilp.github.io/design-patterns/categories/architectural + https://saumilp.github.io/design-patterns/categories/enterprise-integration + https://saumilp.github.io/design-patterns/categories/reliability + https://saumilp.github.io/design-patterns/categories/miscellaneous + https://saumilp.github.io/design-patterns/patterns/abstract-factory + https://saumilp.github.io/design-patterns/patterns/adapter + https://saumilp.github.io/design-patterns/patterns/bridge + https://saumilp.github.io/design-patterns/patterns/builder + https://saumilp.github.io/design-patterns/patterns/chain + https://saumilp.github.io/design-patterns/patterns/command + https://saumilp.github.io/design-patterns/patterns/composite + https://saumilp.github.io/design-patterns/patterns/decorator + https://saumilp.github.io/design-patterns/patterns/facade + https://saumilp.github.io/design-patterns/patterns/factory-method + https://saumilp.github.io/design-patterns/patterns/flyweight + https://saumilp.github.io/design-patterns/patterns/interpreter + https://saumilp.github.io/design-patterns/patterns/iterator + https://saumilp.github.io/design-patterns/patterns/mediator + https://saumilp.github.io/design-patterns/patterns/memento + https://saumilp.github.io/design-patterns/patterns/observer + https://saumilp.github.io/design-patterns/patterns/prototype + https://saumilp.github.io/design-patterns/patterns/proxy + https://saumilp.github.io/design-patterns/patterns/singleton + https://saumilp.github.io/design-patterns/patterns/state + https://saumilp.github.io/design-patterns/patterns/strategy + https://saumilp.github.io/design-patterns/patterns/template-method + https://saumilp.github.io/design-patterns/patterns/visitor + https://saumilp.github.io/design-patterns/patterns/model-view-presenter + https://saumilp.github.io/design-patterns/patterns/service-locator + https://saumilp.github.io/design-patterns/patterns/state-machine + https://saumilp.github.io/design-patterns/patterns/cqrs + https://saumilp.github.io/design-patterns/patterns/pipes-and-filters + https://saumilp.github.io/design-patterns/patterns/saga + https://saumilp.github.io/design-patterns/patterns/transactional-outbox + https://saumilp.github.io/design-patterns/patterns/bulkhead + https://saumilp.github.io/design-patterns/patterns/circuit-breaker + https://saumilp.github.io/design-patterns/patterns/double-checked-locking + https://saumilp.github.io/design-patterns/patterns/hedge-requests + https://saumilp.github.io/design-patterns/patterns/idempotency-keys + https://saumilp.github.io/design-patterns/patterns/nullobject + https://saumilp.github.io/design-patterns/patterns/rate-limiter + https://saumilp.github.io/design-patterns/patterns/retry-backoff + https://saumilp.github.io/design-patterns/patterns/timeout-deadline-propagation + https://saumilp.github.io/design-patterns/patterns/filter + https://saumilp.github.io/design-patterns/patterns/lazy-sequence + https://saumilp.github.io/design-patterns/patterns/method-object + https://saumilp.github.io/design-patterns/patterns/servant + diff --git a/site/public/social-card.png b/site/public/social-card.png new file mode 100644 index 0000000000000000000000000000000000000000..686729f973c7ee482b2491b68b6d436058b7c73e GIT binary patch literal 36500 zcmeFZ2UL@3w>E4*iXdWiC`uc_HXx!ffPld0D9m6ROOl5o34Nq1Qlv%^MXC)I1Q}(} zF?k>lAU!~c6hVrLiF5=Mln96jq4Vu{-m{LN-&*fF=Ue}`*8l%mOI<2Yx%a)xwXc2M zx%9_Db18|n5=)jWk^23&Jx7)-S&A)LBIGA73jcEGmmr%ZOX945-?QsjKmsA-p2KPcQ1Gri=~d@+C_xw?P=$-8#RAD5ltJAKK(&x>D9~6 z&M!S3b~aPwdfD!MFAJaMXsh+dbjL>OtLmh8RXQ}eotbF4@&Oqe?honJ$}l|+=6EP6dtct5dqVZ}FNe)g|4&{kvPGJ@==DS<$Ze`$i-1*;&@_ZFcIY{uD16R_O7O!m1sO{g5vdVAc^SeQ&vhv&L z{%>FVze!x7zkFlxe>>@Yd+qlV!}k{V@0nZ@`G4;-X8sS`+4L24>{!3)94GC65=8%g z;xhelaSZ%VuKiwONcCrF|7WR=+3tL}TJ&45Q9J*=I`-d=5~!d5?Q8%42s0JHkMF^w z|2t9qe>%ecAHr|n8c+~>Jyq;p*QP|H=wr=e%E1nsi<dO$9e$S5!tp+%FLaw6h&k@(d zLd2Bs-ulW+v^+!hCki3+}4pjW}MITwM>?H|%R){bFBoBvnQ} zy|(U0N{Q?$Y&WcF0W=o)`i&>^0sVKTRZ_$LQD2Uv?p=TE?LliRgZPe zPgHE#k0u4N)KzlL@EWGhld}tY!7uxEC9GQKXt%3*{~a;Ey6wp9I`_Gs5@T&yQ;(BX ziJ>ox_zeHkLn+HFx4XR^ak1z~{LXIr z-!N6Pigk8zaq9Oe@g`{6=B}h^_sxb`IQQl@UYxgaZjH10y`t4%bq-NEOwU*6>G0RC zE@(TJ47rEZrVx9dyRJlwaoXgSt^It7+*B_E#A(k%Qf>Y8{Pq2-Fq5qY2QFsZi_CSC&msEn z)Gtmu#uQo6Q0D67ch{AlId-`R;iSc+aydyQYwB-yg}5~*oV%G)vQ74p-`fhbh9SSz;>o9Bt*=)Hu!gLdY2j`?#^&TX ziteKApd?5UPYMx6adi83n*5_9YFy!BBe&H!jrER$Hve4yW}&(X7;MswbuHJ)uTmd&YkcdFNNoaEp9 z+H1(HB8Ay?-Rh&aUJtc+=V~WCIsl$85lhrO|M1co-5`N+Tx^X@XZmL>|Ncu?88aE4 zZM=OE?`G&YnE69?tD)7q#T&-+{PaqS^ivzL=EL9t?g*=eDx-!Fq>tV`Y69h=kZsTX zk+K2rHvA%D%lzD@uOn9y@eePn@y<286_Qvjd`QKBq+_Kk_pntOQg_DZTM0|i_-Y|; zr`;2aSj(UIj`cc@lhcc;OUL^;JEnS2HG#XmyhNv)CdW7xCwj*uFf$Z$-Eu6YK3O_+ zq1sJ*UP{Cx3Xd6^4=Qh0+>1Kz=Dy4S#>!8n zH-9d8{qYXnu-i3EyN&lF=GldgN98n_};poB5QEPI{aBkxP-F;&GLlJ05-hg49AO> z6(*j1rmm3lNtmeJ5h=6DF;D<=or?Fd~UO9nfkmk}%mSubep)^6rv_ zTvn=yUuidmu*A&&h#2_5Om_btI9d$D9&rrFRGH3M`fp9>gDyl+U15KjiN_SOQR^T_V~Nd|%}> znYaqOvsv8o8s5#PL5~ZWalOuROHST*?p;ql!=r7s8GI^5dOxE6VfXlYD4@jdy92XN zM$4bpd=}z9O^v8;zXypbX*n{vj#nxseN4jgM76|lOSaAi`-HBlPy7WC#&icI@l2ym zN`lgC%cOhQ9Ul5&ZQW=}!dN-;nPp2yiky)~km%?U7pGxL=+(N?p_!i(XFDb>wGW-{ z?@u%Ms9&PBEUs_n&$t7P5j6(N+GNMZOEjOX@zakv?R~i;g?~6S$ki2gy2sRyrKhojhZiQ5+=@FVf~pk@Y~o=a+s=U=9BGiD>3%gP?dN@%;#6)^DK5y-r#;`RmZ_w zQkEk4r(FvGbtulw&gHX8UvagFj+QGU+c#l#=Fs3p`hj>wR4G&7uk1ewMu^fSQ zI`fNKE9TDxS}n8I4F|7?8m_gFv<$Ocne}Nm*SO6u!W?}m*;%rXo)keNI*ZntYBx(F zXUs)4ypE>}?!MDg%PNCpw1{e`85VTc$xDe7)xD8QzRq# zGH3Rx-Mfh4GwXO-`8yNw*)QT{I&+FNHrNlUhy3mR887@z?x>6+Iq;8Xpr$GTj@TP6 zN6lem;Q7!_nN2naJgg6hqO|Agp?|qS3gLR^YaoZ#l2smCkZ zkcZ|H(>S+&oka5HZx`dw9O&|gbksy%v)@P?apKWbGM#$~v);NAh@8eA`bK-s8P*8r&1TR$QW83}{DwM;HnkMA=J}tt@lG#0ncEsqbUPHImzl>;I@`9l|v4JZnu_%wDu+uI~~GT6(+aOUmD z)Tal0&eH4BKjz@*GdGtP>qH@k{O3+RJ(_mrV@+qfevIYs&x%|;_6E-n~ZlGO-S@p0_Phh7OllVhK*uyD(ezH6)bZl zd#u@m9)42fGJWTIWNwhQee6XvCQ^4MvivF(5!0`^d=d0*@DiO7SCX^9@4#y574+G( z-g9m;d6~*jBT4wj04q~W&OF@xC~74wj&oa@d~oA3M6RkYSoo-^^II|WVcG@VU%8v@ zoxB{zgos`idr*%YJk+ZjKif}E*L($~v?!Wg!naJccf^o*vjMq5shz;z?__U6f)=q`uJNrPhv2G8n zpwlP{v1~&U%_Yq7bUCbQxUx1H;V*P^0rouE!wJ7TqTW(u)iT{Q6Ce}d=-t%YIPR=% zt1FkeQHc0Q0Zl%`bq|d>S+5}%*mRIZTlI*o%7x6CFcD~X_(|;wKk1o9(-t-mFhP*Z*{nvl^K#1u9Ho=UUG+X=n!CGAwuRui1VGl}D~TSl|T*=phO4=U+V)}(YcXY-MIQS|C_S~^8Wi=w+G zul6F^LiOG1twx{G;}{Da+}XAtVEHQORDyuidVCl!RC!KK$jSA)76_X;j}0M_5rxxomr4Aj@^DqZB}- z_@QWMbf~$u>+H`gpthjl{pA-HO@&c(n*?{hbMnibe=--<9}LKx3?O)y5msSVQAC;D zgu|>Uk2IWy*|S<{%SjyF@rgPHN-r}IN5Ax^%yweB7%D)-+g)UhoI_4eJY99O zR4xMj=z)5&YGaYTeETsie{#z-yRLHR=?{RP-h4#{$YHX>xc!Ps=zlEa(9D5yr@=-M=ojkIRKBUJDVuZFA z^0PwHE)%xH#&8FwUVNKlDg&21yqWhZn$%HGPY@1U?QJ>zqYWpLwAY$s9-Wu@A|Jhg zqaS(Xs(SGF05dE*07{!{JypiYH9^u6eC=mP5qF2Tdtg;bmyq}y@krZv$+n=vpx-J2 zDceTIm3i6CQ3I}zpN&VsZna)B)-gEUWN9wgGmCLNw z;WdEGX|Ad@IkH0nnReTY9%flJM1B(+^3s2m!(K40j3@Fd$!irW=qZi*m@h$7uo>ro z(?NVc9Z?&-O}hHK5I0>`m6&pi@B!xlz@5+bBT#xx^ z9l7FHaft1L@t_d5V|2;x9?p=}2(9=GbaEfGr0!SI|6(jBwil^S?k#WfvU#{BBPr?_ z`F`U=M=-Zl1eLR=ndZm*nD+SQzK~q3Q;+-ZH#;qg(_XZitwz+Mqz9*L)3^8dDeBv2 zeOeMYzbl~sjhxugUe29b!83EG-h^o?F|0a@)C-bBNtw(mOv35$99G z?(KM^w28%OVyrdZ5Y;9(ueub0k3p*6_{XxODT z^7{4wa2`eGnr^oD2~v3%w&MH> zh&73+La&KTP{wM_Q4cX&i&;ZE=ZaRMs(r5a!{WsOkt{^)&|0DVP7Lk&;$I%fXb^XzmSwkVgVV)IhzibpNtUfpq zOG!IF7y31ck^cimR0+H9GfXxueYCnVY(CCWxjC^eyx5R$a;t)Vz}nAW&!eNG<&noB zZH*wK+r)8Sy$nB>FqbAP|2yy8TRT&PQw~V`J}5gg_VHRuef-XZy0k-^Mw@kNcFwtb zaqmn{H}okr`sxh_m+B9fjazCz?;*^n zCxSj*GwRgaX1RK__QOkQWcJMD?tx>m;NyY>*>@!*B_UkPcPJ!a_)mZ_b>nmB;6Z2K zZM>8q(o{}{5xlwQVB?LHnw`z5Vtz6A`NI?E=4LI&7w)NM3^idb!|y;9J);-m;86fa zisaTf^Xv2o&6}q_6Me3ODx+niD~Db!)K12zzJ=Wd1XIV^@h1tZ$ePSQv>lzy(Mwc< znjmAV1wGx1CX7VpYHYEWnlt7LeJ$gF240_%UP<3CQ&relt#RW*W*XGOC1$2vhxx z<#d*452yJg%k%Hn0G?I7w~U(A@tQmOFCK&n$|)@Z?NTmWJ5$NN)rRN*V^;xKq4XR; zQg!=ucRLaDEm{kt7C5&SWmd&FXR~dGQ4FcLsh2~UR@bpLUh@N^sM~e0B@9(&#NCJ` zjj%al4{`MOf66HT6XpB^RvIOb*)PpFwNAsBLg=cJh(+Lkk5#n3x}C5o?1kw;=%nnW zp!16a?A(N>7p9%Jr7S2J#2o1#YfDICfCV*ejS2FMqMYZk<_W!=N!cDwdR+jtD;wB^ z6bj)d;_(A1vA^C7YLY_2!y1w%D^Tomf)ciSH*qX-th4)2+8)%71xT)qz6bS-TNQZr zYju$%qPY~6=i4eJm+)PoDmBECI=pkA&(@N!2N1eT>F2bT_d(LHB4|eZ7ivU6R>b4$}MzYd~z<)|1cgb5~)?@|ZGv8-*1T8k7L0V2)_nhWb${lnCh*4G*IKewJCE#Gj_9fa z6+Cz-9`W7k>-GNI2U1uP#)bu2^Y17T``W5|39c-|t9YzWneifCJWhyM<4xFPRbuIs zd7y4Hr9*zsr}<~4oZ1M~mSuSQp<_i6Vq^~)h=%8J;*B&8&7S^b&qpH(119MBw|g|A z@=HrvIF4_dQ2b~%B2lt!lMt~bfY6sc&YaFvKTn57#J`Q^i4_q8X=141VU5r_NK!G; zoes)BDaQYYpBskEjAl`Fm9i{4FXpaVo7JPV;j>Wh0`!%%42d8s?FTcCchX&ahD+9# zjY9voHkKr(a0&bZ`rd@R44N4|dD|Fq!krnIs}D5Ue1GDJpZ`p_WVu0zxDT(POM!MM znW{VM#2&a=lpl8enPkiYs2w%Eq$;1GuB5b_$)~-3G5#KwBg_r%Av`%wvgF$UfQ;%^ z{~0MEgaM4Xj>%{^z7-LyMIi=B1i>`VX~MH}soq(b~2UpLR`-FaI{Kg@F7 zZu?eg&GPo5Bypr{h8A4ly58!zmhN7hhSxbZG2<2>j8OkKfg`UZ929>_UV)gK#;(c& z3cB#6v5|f5$#2Y+^h)?iK|x5<=Wzl&#ei=s)yr{v{{_%IkNth$T80^p?pgr-oscT0 zZBi%la2aDIW+9eQwVMc_W@0HZ7bA6REQkLDsJ(!js^QtR!Q|W zZ;W#>q8kCjI24?jQ^cEe1p*ZXP|-!-n*+L#lzP3tsqe9UE75|+~FPvn1g@ekvsD%58V?QFB`Xi4qt ziZYrRzWXm>>z4QJEeenTJQ;zfx4rJ9kL+vPq=)SW+*NRfFjY!tG9<_KGXfP5f?g)g z-LgapCJRaXv(Ne(J7w-otgA;~C|JI~S+Yq1nIx;%8681mnj}7p%S$ItXyu{;SjNxtd52i1`%1% zGiD2MFG0okS0O%RtkNrvc)KXsa{`taxq6bFY}#$TPjA~|o4yqNE5O&TbVR-P-1txk zk;5jmK(TzVd!r|dru@j+p7`)`f(!;+&959m;^jmmB~;%XYLv0~Re*#=x1MHT-#mm6 zwq#cuDQHtZ<5c{L`|jieN=nJGq{=oDTsm-ML{6+PYDq(MJA|VX4Wu9sGU^r{xzsS``gC`FZrpB zWPK!$VQA#*2(p|t#G!-R9 z_v0II^u7|(Y`|FP(-E2+)>+u%T|iTzx59A9fq2OwLI=k)8zM>EjzU)B=w=n*h6lXt zGO9Y*pB5D=nh5%$jdbYe{E&n*r$5fPvuMF5g4#x0KNY-oWT~%#P_#;rAn5D#r;)rq z_wmikl;(V<9<9l#^>Ww%ef&%$!Tb8hl3o`dRpLa50GYX0B=vr4pdsALj?%!*PSfgR zJ>xDey@bj^aHXiw6G0ULgpU#Bhgs@TB;C9W*Yh-hX<&b7ttF5_GxQ~uu+BaKmKDEB zFaI0&NsvZ*+ep$?ouw9WD>jY{xL+5vK(N|eEe|g(Tksu9L16Kof~YlU=kI-wvnJo= zDwMnzLFY_e4u1Yi#!JCXo8lCKP6$Xk)jjBXN{H1NNjIQWl{Um=MQm80P?tmwtNgOB zjnp!tKKSl+f1$b9QDI_45TmD(PEQ9S(#nH5>TAZNt;`(QLx1=S;pcQA;=_M92cN9n z14t!s%#|k~PEWCTbUK-QY}Q(X(Oct5Jq~&)84m{AjA~=JL&I62CVFu z168zG|FW%k#%?x&BSmNItN)QWJNi8A_hpFXQC;UsamzJ0-n;sC#t(Yn!BmsU> zEf&;9GN=}Nbw6G@uOviwva)MFiCcAWDH_qiUMr0lEsW9r)!3cE_UTtfH++V=T0lZ!Gym>&VAwPa zMe@e=8F_;WN=h~%_f!}wPV0G?Li>90&Ik9viHGZLjbC&Cf={fzqtsS9wZ&=L)pc~> zV_{2xucNw+l(Rfm`r9((M75~a1|2+By8jaCrj8yXGX}hFO|>Y)se;a11HvTYW2(#y zq5N4;MwC5AzlLe;VG=mV>zsitf`}d8BVqlJ@7VE=Oirk&EM|u1SwT{evV1^ycK{Cj z^LcmsSdk3C)2XYlst50O^UMFNo(t@ zQMN{6x%oQLE6n1-GxP7fo*kKAz(A7k6$%S+N7JaePJD#bYGi0wkR5jV(2g_#L|?k#ECb*> zCe(}+5bflJ$*2N>mhw+oM8aAuuA+rKuoq=g6LKSRb%VdD zLlWXh@l`6v$OOSca;>lsjx=&@g!XWd{`^XL>?_7nsJbNP)LgN3;pk)ke98G&$8NWc z^-q78?C!cc*`#7VpKP2j>o@ngdSrg8OXopgg@vibEhVhh-7ZCHIl{@uwAF}DwzGFt ztil!+5Gx!H49{sRZ8gpdN$?5&c=vN}`05c_#321Is!ZT8;eA@T-EC3?jyK&Fjn6FA z(titFt7t|IH9;wBz{CFSQZxy#p#yv>+wfZ*vSuKAG(Ok-*;dq*X^Ydy2dvc}~0gBmI2%mUJ?DVcv;ZpRv^qVE#?c4#zyh4R5=NJ0;R!de?m zTHQuEaWk*KijGocWEri?kiiS|37lK$cAzObYQ+&tyvCa&e5#;)L35h6L5SP^3FoHw zzxT{wmenC4B6plK&^*o=uWT!oScatMGl1y5Z8t&-`aQ@8=VsDPgKQM~#A2or@78C} zPmYv11?Bfzs>mMn8Pzv$QWIPcy#A9A_eKiHEEl05^_?co#)i<4w|$C}<~ElGYPwAi zjJCFshEpNO+#MM>mXH?yDm$Oid2qg!qJwh_?WUzrIkrz~rIGxNLfpi5Dq+Y3Vh_f+ zt|F+sHL|N({FP2TK67Ys11u3I-5`pdsusHzFm{49&T)x#C;NtTsuW0)Ld5#Ca4({P zAtXWR&^1PsdQ+QR1uRJ#m`EPcf<^OD0h%}pi}0O#83Clay{8>uYW|AZbqD&;VVc^qxhksJ zbWGX|Yx^&1wlzj4D12Uc8kOK3jFp9OVo7OK4tt!F^td@zwzTat5h!+&it0)#zBSSc#2V^5Yoxp;fUu52Xe}+e zTo?lIT-B3I*kO39E;b2FB{oiaMGpZ=>^^rv4Zl7}2kM}yhmb<`4Z7RQ=~)W14LVFOeXe`|fJvwl z%Vi;DDjBuCmgQFOvPOnWK3%k^7Qcw&;TG8j5YxtZ>5VvEI=eS~SZT`f2gZu}=}+U) zI2^ruke>e-0I>*Kxq=kE2J_69$7&Tf)OE5YRv;qQ$OCdCz+MkKC5tZh+P&yG20l&< zJ-*<8OPRpt-c3JJV!g;24azF8<_u+(nR~}rR>^~)-U|6h&&IhK^bq{#K6}kt-lF;z zLvvp;E(_qD7Agn*qM^}Ehw~4u5sk@e@rCE+aBl8ZandFQCbHQ0X(FF_J!GEqa-1;J z8$OoD0L*{1jkKYcfKtb1d&JOg(+73;%u#t5huOz^*`uM-b$(KJS=qmk_&Z@l8Tp;l+$h?JVg%PNStXa5&+Rvk=!N zUiuE?iA`Ft#p5I82JYlpnmfztO~9DLz%fXGRcJGgM-Rlixk^H%NI~(Kx`$n*so9Rz zS*POg5(^H#2@%U@NkLUGT^6|HSPffQ1?KYknQv88+)qub_rIfP>(fP0k>$iJVWQDG zklFg)uMl|6-exvU1xxzklD*&9T;tuu>zA_tU8idHum&pW;E6A(oaT}8o~LbM)uP2X zx5N32C}Hkk3pJPZoOTIN#FMBsSdWL@TT%2{mJqk4P+9Fm{nM}~C1L`Z!)N6!T9mJ- zF&sT&nxW^>c6%v0H&V{Go!p^ADGB>?Bu@IED0=y6n}a(!qMAMfZr_08Ra>n#qUb7Q zLs#Y^RQ4O>-2^DmLfouMNu(q);iNRoQ;)F%SqrlC{MHr7dp;Sc`_A>068kNrCSvkcZ6hk%A6SrcVbWeOq)8k7VBGh{>=Cg-|A-)6Jn zvH{ypljX?6HWC5SShd(F@EarL`bUI_;cX-prjL%kV3f1>63O&@ed=6>snk+XOcH}| zy!~xB-b715wYXYWI5@FJW%&a3KP@# zWX=u~FeO3DOC_GnrKDk&;4NgT;wKWsk;V7w{Sy6yw(mc$+Z32%0#}xJpf!xmW{QTVjl4yINP6 z?>&2#>%au%(jZ+rXw)~9HC6hM%CUjw9g|(>NPr&ho~NCR7>YTZPsH(>?K{I^#9R`& zxD{=|xiv!QHBU3P62+k{kv1!2&N}a66?Gh8xtiEQ!^GK5{Gf>fdY+Ocdb11-9#9E< zWvG5`(F+cYbOpd&S|)8=d|!>$pk>c2kB4RD6irt)4BWYC_&_?WGn!PBtWf{FJXxha zOEM+4Tv4S?F3sS1O7u0KY@?eS`;YmTCMUnrYHUy-RrR@Qd&SjTzjE#$4papj>*)uL7GEmdu2Xhq+FsjBsxP`bd8py`(b1|28~J+P8Xwnf z{hRvVd`{*in_Ssm{h)u;G44S9^GB1Y&(v>KiZFoVj{>`X`*`DqrrF!MK4<6eul?6q z`>PE-o)j6I*UCj_p^|-cFPvt?Rg}%srpL+?rBKMDY98cRJ?uq31Ab1o%$HLqO3d{@ z5o_eG0-`bo1ZF-K6_3B~Ng?bo+mUrP_dK5hO2h24xyf>c)5AZ0H6SwD-OLslf;sUA z$@ZsRVFUvT$Iv7|&4^O68hShxX~cBvaV7{^!{X!xaeY7p?Qu9iT++FlKW0WStM4fd(jBp{vhw9OpH^Lvb=&jxVZS+4r_3ClpFK%a3M8ZHUl zT5F7SIGnEuK|DIcW%^b5cC1$Q1w2Pr2WUej&%-ozBUu?(^}|};rZ-hER~41z%MeXv zmHjQHQy)7RKD`7r9PgshI?8N;Bc%NR9Pd~?)t70{GJG+&cW6 z0>^p*|Lru9F9;dyF7EnS5esF8Lzc(W-C0wcUuat4m*gVla+Ls;*R3!RxDazjJF|$V`_$M zrKETasq)_~#xe6LDwyAWG1LQ^p55fvo$*8kFS2yO{D5l&l`ua+p$k^3OPOun%_>q_ zM@cX;Yqnw;a*wcR-dCm}4okK0fw-^a_s}QiGd7m~QeblO>@<{j*m6_x6^K+v7@=q4 z^&Zxgi8Cw7i|J}g(Ur@hffhe$1@Zv?Y`ihF@BAXu>B?Y!`ihuq@L8-%WN0;xH>M5P zXPVKeiN``GPL{{7m^1KQiUtbs6TQzEI5^(Kso+c4w#6AqivsCIa#Vz^1%>s-aGC1{ zO0HriKv&S+fJiFnAdc4#NbN@1o*j5BZ(+IiKf!8+zDrL^h-;xw8Qdqt)o{SMEi3z_ z*@mU=KTqI}K&v!mLS(r*Ob;~f8hv0o*L-_^wEDRzzb{S-(NF6PC;UW7i2>IxdUAYG z9zG?^4Trn&n8L(2S}X5>E$~~tyrThYScD+VHQxt_T4LekNQkQ{ zh8oKVb6X(Um20hZ7DJom3P{ECu7yIx0BEKU0anbq%yDED9oME1zzgKDgJ6l&dj7ui z7i(?a+=10DE@+piW1+vXl1Amk!B+Be1zpL%vXUH_Q%xV1ilGL3&~!W*FK7{kJe*C<_1HqmsDeXbBx$5tZaXC;mx^=C>LHwDxvJTNmwAeb zq47)6wK$&i0vDX`P{RD;prd?G&Gnzd@qp$ZbDE)Yo{0?YTZ7I0ph1C-vqw=4Rl#-- zmAmesr2M&qqO?^34minSdCL|+1%EOe1&hP+BB{BGIJzz9s*y0;2~B}LHz~jbZ|Neq z#mf{&`cDaQBm9JjeRARqy%`alrvwCnBXdCGYqvT9nW#R`P&Yxsgt{e zxuj@0EKYOR;;aone1n=Gi_M+x7e!5%!QU1%YGJD|uHVjAEvM%jDig*0HjKUwbZNTL zk#fL#9O%f7rWU4$m&<5gNJ_oNwBc;_*BltzjJG1*FllRQ7SYofv+*tV| zt(B#EGK>`uD(GrQN8s4%hUWv}-8LVBz3l_1p1bZK9|VmI%!_LgR*|6$mI>1;-cg*} zCn3Ic*cpeP%LW?ipYN}x``_>36nB}4Bc^66kgz*GtSKKJj=tFuX4Y*YaMZ@_yh@4H zR{N6qslpZm-CK?3KH5$PPxt3^o)#t!r^Y|1%gVXt^RrW2u%Xe#YBlZyxF#6VMYH2l z^neDO84I!n0Z?9X&Iw+iwl&x2wsL#I{$a0{hRUgFLtRNe|EoEAs;R@$Ex3KKSMbME z$y@*RUu40*q0ppAgK;-}v(-cjYijqGAAulzeqWedJtoYRT|`eR2J%?kj8nU%1na<24oQQ%aQ9VxE0VQ7?EGjh&Pf!ApJBf6NsdQU>EzW46b~ zslK|NtSN#5)cQA|2eOA*$bky_84*;$-;8Cb`t95P!3r#MXBj5SVOtv^`i&K^P8k55 zlvxag@qWrmZ0--xB!BIJ@LKg^sE+}Tx7!Em4y-a3iunCF{M<7~mQ~##{jC&|s_DfF zv|OA5kLprFj+j!EJdG$JiK{V)VktB9BXtZoSs4aUN2{g8(8u7T+x|;=Qby(U$rAM` z#yga-@dmi|IEy+)B(iAp8`zc0kufzQ!gAHN)r4h?(I-JT7T`PM&ZLf6J;u4w7hqZ~ z3X~~s7Bv@6P)zOIM2WC@V=_$j4N;|pU@HOJTO+0w;>dw&`bJ@H#tR%T2DDO?jD_EM z1R`YCQ~-$g%WsN91N8EqDC#A6C2pWW!A7=E3-nyr4Z9Rc}CwFY=Hc_bO#QiWRde( zq14=mP>HOXaJ(KNQB(n#8OfDd_s?;EJUE*w5=Yv%8hg>hQ55C|L2bMXrReq|I{+3k z9$ki**Dgg_K^WB8x5-q(+kNNB&@Bybae$*4SrWqBGF^j{f|^o9*h(Q3u#7idl39|SWipM1xtU+%THUKqr4W=4$2^%sNa| zfsZU(Sh8pQ!Dui)&KuijbuiPIuLn~Z1 z+uT#9L+QBX#WKWirzl-og8{9=q<(eSK?FS`imH=Uci!}o=0>zc5)3KFY0AKFNE6$s zxjXP~CO8dGW|9<=uL>Cn2eZq^IE@}TaW@gv^t>3VxhO;HPOP#6M6({yH^2m7Vt$h= zEISGwRQ3-Jj!6Ss$|uV}v6L%t5k(#F!dy4_^>l;q!n8ZDq>K%zlsyT7s6Czy`s&>* zTELZ{j3DSJunRa|F@kfm#k-xlaQI;^RmRk|QXC<~Nqhbvf?o4jiXNhip(K$76>%7)x-CN?JWTz!I`J^I^|R8HB5tBZZ%9@lULWy1O=B`^xX_E+@3_< z;L}IaHy>@Flq%O3chxm8%9QHo-!+u&Zqq-uGOuVe{QKD- zl51~W>u>7c*3!dDqjS$DWJQe4rWBm@ zEzTOG*GQq(A_@qQHpEtzMN6qfD@clk_{mx;Z*;P(GN&0c{+GX+o+zzz-$EI@v=Wo; z-go{cFn1q~5z;;}lvXW%TN241J_qwb=2{WdIzfn-07Df(;n0sEFv@D!3J4 z)S)O@U)Nf>FcyWNyRV&FWtW4ar$@IR5?zYkb2#rs*l9NL^fGnK7m{Nro(@BUgG?GU z5y~oClrZf$0juzb3DND1!1{|I6FyfzZ-+p}>3@OgDq-)#8y3V6=Im$=?wX!33$*QyJKsS`zSnp(C7VK5!6 z09ym+7LfKMrNi|nO0Ha1j|ed6(WH|?+_4wHhl`-ez2O{?L-WZ5@o(~|KP#y~Oz^@A z<|gE4R2jdRZMqcQ(3ow(k{bGykXL(H>XAs7mIbTGxH^EaokHj=P1BQ`ek!uIvhLc`{s zmWH$J9=0816N)BGFzcuUp1d7X6HbQt!bB}3e+i!MSf{=M$xmyPmQ=ymc?`W3$1i1v zBmfP!6$0+DU}Svb!^B?;F@?;me0Lyp#c&9LYm8ip$6tVc?q(sWSkg_8(gDZCW6ja4 z>v+@ms2u5iVeT7=xp)RtOW-a6kmX=hnXw7Vn`y>wA#V7h3Xu>b%`JtLyB^*;dHqtH}Z;vF7UJ0=hpsVz4<7vgR zC=>%V3UPcB-fi&G1fQa0^6K4o81o#r!Zc9@5gd=3EKHoe%rRrR8rs4w^x&*(Y;QP7 zZ-z$7MTNNcImRHJfH{&RQhbNpI?Y&ACW#QtOVQN*OVN5aF=(xNl+9@m&(v(YC?Vp zh`4ouY!gEd-Rlg?J>jvEu>k*uexW!lac-mI;n86+A1eY_Q72=zotD%X+}s`eG7?y| zdR==N^NeO-Yz!*saIB(X9FnJc76@uaa^Ooc&cdjwm-Bg~JZpOKt=(L+hs!~>@=);J zW6#QasJi(M=jED&x%b@dX0>;-tp17AHOPW?z$bHrsfD~Uc0qlCB<-|CxIt!x0PwPNU7IDP2-5?;4X(+b2w95^~!IS48x@Ozk*Zlh?zY}1wr8?mNZ zY}2Cdw~Pu|A}>Y+J?C&92K$rU4_uYiW|$yw>tsU;@bI#O6BDjDw-Gfi5Mb7tVrZbb z*r5j^sDwXRMihMqqOWQ(ed9;|TPQM$D(!}?rE39}EtE{tU(0uIrZ~a4Q4uCcq9`0U z;k@3?{&cg@i}@T{GcP*=Q<@IE5G3@DdKh$HzqA@-$E`41hB%Cr^ysDuimBhusFe1`x52 zp0*3;V{j0aZjIRCH4d_@m>%dPnCSVYofLwxVSv*{Tfz$D=m<@LUMq?sH}ky$1IQLY z2?k@+`M)iyO>k#$*d7LcJP(_K5KcRke>yP;hN+w3D_87tgH(u2kX&Vzx*1V4T?*9Y zu(=YV0I`$JT1r8DrRh!{>*4%Jf%(to1w~&HDX$h6!)c7kce~DQXM3`WhM&8rE2_oh zM?eT}HEU%@L0uL_E072CDA>N$D>ag2SuI9l3((O* z7+(f*)EErNtPc-^!9h=hNHQ@fR}<}_%DmrfS2>LVfZ3o59g95XnX5O6<8^_gm=mBY zi>bPkfzgo7XDCZFm)07XG?y?JiN!Oh9AlxT*(k1d{cF=bp6^9bIm6p|e)HkZrj(2i zgYLG2VrcGcN`2cjj&~PU*NJDt@8+pP?x7#vH-y9+Ukj1uc9+Lg(*?h-Q+4r-7eIxj z#Cp1eY+mjt99g{XaGrdyl0L`00w~zomQ{44FoI*lN*eA!ph2|GI5bI3Sj7nRadHLe z$5kn`5iqW6h2ib}&yNg3_M#Vt9aHN~1?QQ}`Ta}L5fFQ0eg~A+EtaO7%fo=u;a>lefkmwm zX%{cM4*oT5aKyOl5wBiVvwOK-W7))*lJLBQRPKVX4-=)EA)?#|+@)(~$jVTRJ z73MyO^&r<*(FHNvgwt@Cu3g05N|>0zS5;X1^{c4aJT)@gQ5cb+lGWp72e>F2qb5x4 zWnYd2)-LnL4vQU=PHgE=gCw1@xxCSCEw7k9Qj?F*&%^s0U%emo^e_EMzig->zkIaq zRq6YBQrqL*_y(845Kr~ra9gthE!D?NpQ{s4pDL^ zFXS;y)>P8l2kBW6}9$uDFhPBwBOFQ zT3PONIMsJ1I?x)v7h>73Lyu`HSq(E&w>#$*6|<67SU$Al-M$VjhZi6`-%G#gKJW&w zau(+1#w=s<2mTm&F2L8!gDh9)Y1bwP&@TTO3-b9Es9X!qYh{R{{nO-^R_yo6>)Lgj zS*=ad2&Z&UbIP=Gklr%*%C}dAUe%*AWo7}Tuieg*|6YoM=y!H)_od4W{Dt5vA1&tO zmW7vE?2y5x@VvU>uFnqK*yKoGoscN_0)x_rDp?!*+B%o_90h!ROv4r^bp2C3gj`Ur zt5Q-jVGKAqR^F)H%c;P_!S$acklCM_OItrTuTD7-Ki+?3wq_?Y?1SWaAW8Fv6{aP+ zJLlxYr*&q8?85Svm+mew8JA%nPf4F!@ZAVydq(B<%`Xwfxvk8~8$6&2Bv-}T=}h&EkG9hlmU4vs=2d zk2;r0A-_|m`W@z1tvj-J1&JYZ5t@`-{07_O4KV-C1EEtN2~vBK-TUwO|K5}rY=v<)Ps zR0nknI2pi_+7{4c83(>Mu2|JVZ8K2T%Zw8#IPXI3Iin?E?JGlVODEE+FcHExZI>D@Vf>?JtkdKHWKJ`N?K6 zFxsfJ0M=Im+vY>0uHypbgI&|4IuA>s)Dvxf$2(L3;|g>|$y3*F=i~4jM^9;4WUio} z7s3a7g0X31BhmGQdI-&CMyJ9M0%5ylx!a+gsU(QJYcnt?6+;k~3aAwD&80!q^iXnV z4Bd@oMAWbrE<=kSQx$SVj(78(6^6<_vF$?2iaDM|4tq#8BB->k=xJe;RN!DeXA;p~ z^VXOW9j}-Y!xNn>fsG+W?$N1_vGY-hr2>vo{ASu0X8oGaZptjr7P+;N-w{zA^|-a$ ztC|4)J3TtYoRH;oBO$JP0jz$v2r>xF8zi+aawCg7?EK_=s58p9_r-|aw5i>=+jMgJ zxwf|6`vtc(lM0VSRWjoP)7=u%2cc^t=KfAmx6M)6iCts%O|h|bouSH4{H){AmoJ*` zuZZ(V?CPn#n7yYt@FktKS!;UTC1|(4cc-(*KR0R*OTIePZxrJlW~O}CF{U}Onp3lT zatsK$sN2_zx?R3taO7p~>s4_voFo{s&zK#27#sRvakfolC2 zjt}Hc^U^)GDqrA^0D8?M&v)n8+e!Jfp2ZXO_J7^Tps((GPFI%wU^6-yVM?q&k;PDm zf>VQ*-urqs&GR-R`wIE%fg)KvMZeL}*^1J59l*9{JWg}!p6fMML^o7n8mcjOpJtuh zsS*>MW`nb-$N08m9D5ut2sw^Cw`h2Ql=mS`BKT7M`lKZJ*Ae=12h!2^vZ$FlC&CvA{O$PJ5ec$)8rt zf6T|cAVs+(w-n*4$W2e`d?eV9DxU&y8Q^ha@f;@JjC|$CosXQ%J3zO{%&#NV88u6Y zy1N8EoVBEoK2Et$QTk8liVc|hZd9_0sk}i1{w>ygDXfOIk^r{DpI5gAyVX`$IJp+0 zw0H8+cUv94JOZW&+9hj-bpagdl^?O85fA_dxGkhUm%fh=X1@t&B-U}i$#R?8Hlx=P zvl${%J+-&v1C@`gQaTb!T%jwbD}Y^ZwOSd1G$Sdbi3yN8Dleh9<|fCYO8kadKu!(w zkPqoK%^(M$AxWlTfG{Ix)G;Cca{P_78a?OE812K(Ix=FLgziEsT>dMjy#)620bXi+ z;6o|L_79OuBlE5~S!Mz{>~}m*pK>v>fUwv&cN=o~RR|o^snLL!XON+J7qpq_C$okG z(WIGILEXizZLgo&&Nb^f0$6Jaq?^*85GH*&R+_N|(k;S4M5U}$NB}NfgKV{>hMPd? zGE;A?k-)?-<8jXGv>;Q&phU|g-HfQ z#_ORsBzL;5hfDLj;NDV#Wq$ZFlWImR{t_ONFCmC(PT5b=cA!@PidEPRyvt=h@$#3%8oC?3EP2ip#U%|5QBse zB;4I+Bc6Z*se|;9G_t`mcbxGCK>0-uYpk>z%IZFnLNtALf}xOEnXV_CJn>!)aL$zr zi1JU|)ZWxAA^<%YR5*?Llo#2Sg2v*MNTH|dnidgr2WfAZgcZ7?>t_28C=zS<-H>Rk zR8(4(FWHm&d7P2B4qBs4YJyd&8x{GJWZ%{La*93%1Yeu=<-rA*!0{+qD81DT1gT%J}y?AV9GpeTkJ$>t>@-4{#a|uzOaz zNF_xsV;WE^-GRuL!R`{6kpdm`>v(|)D9_9zjv#)I;k3tu?f<-@b`cvdvtQA(HyZLzhKUpc(n&(qB7_#KN;>yn7&peH1EbkUvVn z$4wdAy=^yK*6cleEYzF6a+msS+KbHbc@+vu_rr)3o@Iw`lqI4C)6Ak8&arrz_4VB_55*u7^L9XJVa zhP*#iBG-4iXN;=o@tpwc36o6qXy#CYU8z;M8~CjJ1=zw z#J_d3RDD*~b=^A5?&v;t#R6kH5dq}$bqd)EzwecJm}&XK;*;PgbmP2U({`C1J!^65 zepH?*A%1sURb{z*J7h#wPpNv7daBo#)D{d`*bRjVmG9Nu5w7vt*t^>fxOOyeRjnJ> z9dh*mP9CkAxW2~P`r3jWI}qJ6 ztCh3<_v64pR0z^*=}~+DEgXK_;0vWK2)E|D^MAxkGc``I!c!irse#k|fC!7>TY(Y! z*OLjtsJba(dn-nX1l|48e4upfs`;p&XD0JtL0#RYg4t)c&LKY6l?N2xuvQw!*IH>r z$fss$4TYEQ;1c;5>SS&7kuzF*nqt>faA&%-7-MQo4ZwT0KykE3?KGc4M#BtVx~rA8 zi+=`s;t8?)ZoX`DV<*mBF7SE`ujQVd``YD<#BgZ?U33yA_Ljn*<$<-_)(|P|*beRn z>zIo}4%MrTBlWJLi2+>uL?Qe{K4PVV=s$TjUsRxH=b|!1@Ff zV#ekjfRoDM{F=#qgFZxP!XJM-z11z%J6{SRJ^vSn*5G%EyL$ohlpkMrf30~Z9O1_~ zTQK&yCM}V!=U-Yt+;X150*wG6m|ARSR2@PBvM7q-a!fHhHAg%Ey>vU<} zYu1rnD?pe>J)W4aKeCoP-Q2`Hn|(Y%Y7 z{J5M+AmGIce*O#mxJpORLfUu|_*#^^3XLOa-4$(iLE$6?uDc3Sn}!-z~t z*5Oh0R!&0@*>!xEmQ_cg5ph@*@AW)y+ME?R=Fn=j{(gNc)MQi#WB&jyQ9WskUU;)=-p@U`4Nbt&XBAHI3C6ut2Px6bM4Bco*u zQie*o1y0GNquFJ+Qj#uSf;*9v(iY)s>`g3K8C#&9oo&8_!3Gp%1Eag9e`?%Fi;GZ-<4UObv_YVZ&{%tNY_)j zbVDIL#}%hZnjANcyV~f1TSCA3y1SwOvRyk>bQS~E6+g}q{wpv;5|s5)NXvQN8Meu* zGpKJBAY&w&B~Ihl?Z-ONM9|)2xSea`AqdJey8A@$@YohCT_OCvOMg+EwxP&((o~ zO0ICHO#1mp_~7SiVuykKl4C(#4IDv3F_Fo!c|hdid#T4^bUdYPu)FV541pQr2v+=eU|LH6}o6+R1l|r zaxE+!&U_;rz1JkAVgk`KMVOqg%&oSYG4|Tq7ZF*>`%t)8p`0L`E`(>gf<+-DrC&^V z<3ku4?Eck)+?%<7mcAqP5;sT5#g}c_-F=s12Pwr~^kud>sLt=)2x$LYlICy4HG7qp z4}FVhX?Zwan`f#d#BJ9xI5p|svtb2&2mMCpi^E0Hfe71&kpF~tN~v(iH|~h4#nCp7 zjz`-Z0d5pNbP(<94I*D~c~w8UclbQ7*E?0P(C8cK5Syl$cGYbFa+8j8A1oI%pl-%Pb`M282FK>7A@#*TRX z#`s$KuVZnN+-lMdL2iBf31WQiDq*zg+VP^5FTPpvJj&?Oh2Bch$Ju#a(1t#xvY0sF zqY^z4G`uUi0k|O4S3onoVZ5JAT-qS5pYj{6{w)>wTY?RA#A+0XB zsFE(#6FTJm`s+v{eNpW77xnq=ewo`n+nt=6x^=fN&SNG!rh2!Ru_DR7(=)CXR=GSBep~dyt$-p`{2G4q~01<`8WesE~kFc@t@oAqfhqVWqR3 zK#%+8eRy^qtj<l59?-<~ z%%X>Pr5}I3@55c`k1Q7fTkwv!j)gQEbi*rKk&x7aK+axhMg_}P1hnu#~<+C zl}|itX=>~W@Scv^shl`;da7X>B8`dd?j)O+tmxQgm9EG=^p#O@0bMpiLytb}mAr2k z;E_G0aF12mdGGxtjcAXoLWTSF`3f)k-M#ii)P^T2-s_uuP3eoT4SDf#=inLDso1T5 z-Jch+&A?*w(63w_-(`%>fzl9z)2B9p98aj?M;s}l&5EI2Ik%P?^L#Jen(}ImS$}1H zx{85aN9-G#ua)EZ0}jg{rWqJg;u0OY-Ekv_5j0BU3VGE;UQ2nyUU5zG@U_s^OS__r z2_i2OWAeJ!_vf#?ifoB3_%dDeqiA?jKD#RymG>CID#fz(@*6aG)Zzw-rt9X|`=CHT z|Crt%GatR5pQcv|8YHtS>x-TAy{k#_Q%NW9JE)(ehU3fqWTt2qaCA;`$_eQ_|6aRq zBYk0Yvq#6ktjiG)xatFD+Fu$Sh(-iap&D>MKUF%i!0>mj6Pu>MCn=BE=D0G`zZh@P z3v~fQ*}dUdgJra<^m%wOFrs;XTs%CkN_ue>DgQGrPdtd=#yd4SKI4W9^P=v3?3GOd zsy+#>Nu_Uz?PMmtkT7}s1R*^#b9~Oz{ilmRV4Wsw=*#e0p)y}gTB$dJfQRp@T;Vlert9(j zh^MR^Lt*FEXHnZ15^aj1GZwQnC21nciho7)|-s1uFvZE`!s;h4^o0 zkF!H4=s-Gf$GnkaMJ_hk9GDDQoc60-yFMC?oB_zqLc&{5s&vYZl44F&==J!+fr#ID z%HDZDHXXoY-?kWnEU8%8+%K!}O5VEFxh?GVSb5Em_%u-01s7adJ}D;B-O(ez}CPX!B~}K(zKQ zKNTBh3=gb0!fNBCb!_Ea$_NpK1Y_RClUuK?Xr-C(IjOXhQn(tkhj}9JiVI~WjHmK2ZS*ri<+~dm_{#$&M7np=zQ3YHBL1Eqx=!J<1LGGEsq*I?`2NR0x);O+8w_S(7{5;QtXFTP@KlB>ZHD(SYCt7=UVMt2z4aU@Pf6sZ=>_c`|vxIFa=f4eKgC@$tCyn&%HwIF|9AvEKv zVe=yOzNuk<{iXmCcGIp~9Eo7!H86pm_^~!#!vl_2O-Ld%mpu8h%EqwN9vZu2ZP`dA z)xa!f;{t-CZ+Ezs3In%?baCE~mIc5w^Z>2C%wnD2@ypVI+BNrjGgdqKY6^K%dm%%SGPQ6S1+-Io@XpoF=g>c|R zesRJrFzXQF9{<+hq)dcW)Qu0;MaEhk*2|`hrMhPJ@n+q0RlBcpf$_yirtY?$mU`V( zD5yKb0qP2NN5p%;8^nKcOAp?S?hY5>xo8CoqXpy1dRLL*3nkQMwaLZ0Jq;;*OtuK$XfWG^P5H-@n;g0Rn!pt61(zQZgQEHadGr zC*0CkFHgGwO18nOu|k6AT#EYT$ZUP9|0*tX`J=jEJajW5Lvoq})<1c1W!&?+_ZxjM zJ-=Fnp2kmD^*z6$l5{e}8dQTm8khD{~CnzuVbP?PF!sR(v!iC<%xnmr6*eVI) zKi$o||5y#ei^!Eo#X;aklGI(Qbq2D(rxyO?KW5&{Y*O~YAn&G~TwQxCofOoTWpqB` zW+Ms=1+`U(Z9Hx-sWgByD)BBoo^v>-j+E=#F$XcFpz71dg z956o`w7sHg0i21dxC}T$Urb8Q>YIJ{py2(rzWq%)C| z7OPd&C9zcjudSJD-^+`jVfVAcI2{3nfE48A=qS`}a8Df=;z-?Gz_U%Be~gca;U)AP8m8U9iuD zk(U(I=xO3$go&`5G($mI3m+PQyL4b6BW?Nz+|uYMoUn?_Ynu(u>_`{hMLFka&xPVSa=KwatB`)NU5{J%BE)A%f(laNLhwaXXlrA zJb?6dsE4OLtY${U@Vp8AFLpYpl5TR1A36S$*tlKxjDsJ4U{gxt0qeMH+qk>7H0Jvh zygJ0OF8ImloBdfA*y7QE52Q=1m>Dwg72bT?^rPZq&kqVXUi2-T{E>l+zrcg^$L2+2 zoLN(lTuhYHTwRb_$f<1|NSSWwr0d7Q0k$~Kan?Mph5MDVPEPkMXY|etx8UMuK7O-z zjwpZL+2tD}cxUcFJZh%Z=Wm)j{(+onRnedPxt7w@+n>F5`u3>diK4Vwt0^x|EJN!S zmKeQzrv4ZG#Eoq)ZY(8EV0#9>h|PX}Gd6I?O+bm(YRz=ZcZ6Ha3t86%DrYU29K-3s zyQ<~{Kbu(#1U}@IWB0&;IRg^jB>z#3M?XL3FH9E^--)=OE*=-YnJZ5}eIXiZ0BN*I zm-jP=GSL_2SK7RL8Y4V=?B+#jSH78s63IVV<=TBS=EMIo16c9h*|7X<1ZKo@e1)0W z5&az$D^Mvo!{zcdMp@G$hUMza$SQ2Cov9Y!L$n%ydLMY&%-HAuXi)M&Kl(TRXAt=x z-4*|{9AndrScpGMn558;7-0V3`C2~raj=>*EXKdT7_j+EzOU%tzy6E0m6#Fh@{J&< zCVxmj{`|YcG*7Nw5dG6zWA`dfhz2AjT z5R_={4mtfY_j%WUvKjx^!<$kP-SnRq{=pF#Prg4_PS$C?ElYJ_@5}(96A1X zcjEtrpiBXuloru+08G+sO)$*(hT>)aJ `${siteUrl}/patterns/${pattern.slug}`), + ]; + + return `\n\n${urls + .map((url) => ` ${url}`) + .join("\n")}\n\n`; +} + +async function build() { + const patterns = []; + + for (const categoryFolder of CATEGORY_FOLDERS) { + const categoryPath = path.join(repoRoot, categoryFolder); + const entries = await fs.readdir(categoryPath, { withFileTypes: true }); + const directories = entries + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) + .sort((left, right) => left.localeCompare(right)); + + for (const folderName of directories) { + const patternPath = path.join(categoryPath, folderName); + const readmePath = path.join(patternPath, "README.md"); + + if (!(await exists(readmePath))) { + continue; + } + + const repoPath = `${categoryFolder}/${folderName}`; + const markdownSource = await fs.readFile(readmePath, "utf8"); + const hasTests = await exists(path.join(patternPath, "src/test")); + const demoCodePaths = await listDemoCodePaths(patternPath); + + patterns.push( + await extractPatternMetadata({ + categoryFolder, + folderName, + repoPath, + githubUrl: `https://github.com/SaumilP/design-patterns/tree/main/${repoPath}`, + markdownSource, + hasTests, + demoCodePaths, + }), + ); + } + } + + await fs.mkdir(path.dirname(patternsOutput), { recursive: true }); + await fs.writeFile(patternsOutput, `${JSON.stringify(patterns, null, 2)}\n`, "utf8"); + await fs.writeFile(relatedOutput, "{}\n", "utf8"); + await fs.writeFile(sitemapOutput, buildSitemap(patterns), "utf8"); +} + +await build(); diff --git a/site/scripts/build-related-patterns.mjs b/site/scripts/build-related-patterns.mjs new file mode 100644 index 0000000..f3e4179 --- /dev/null +++ b/site/scripts/build-related-patterns.mjs @@ -0,0 +1,61 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; +import { MANUAL_ALIASES } from "./extract-pattern-metadata.mjs"; + +const siteRoot = process.cwd(); +const patternsPath = path.join(siteRoot, "src/content/patterns.json"); +const relatedOutput = path.join(siteRoot, "src/content/related-patterns.json"); + +const MANUAL_RELATIONS = { + "abstract-factory": ["factory-method", "builder", "prototype"], + observer: ["mediator", "strategy", "state"], + "circuit-breaker": ["retry-backoff", "rate-limiter", "bulkhead"], + "retry-backoff": ["circuit-breaker", "timeout-deadline-propagation", "bulkhead"], + saga: ["cqrs", "transactional-outbox", "pipes-and-filters"], +}; + +function overlap(left, right) { + const rightSet = new Set(right); + return left.filter((item) => rightSet.has(item)).length; +} + +function score(left, right) { + let value = 0; + if (left.category === right.category) value += 10; + if (left.subcategory && left.subcategory === right.subcategory) value += 6; + value += overlap(left.tags, right.tags) * 3; + value += overlap(left.keywords, right.keywords) * 2; + value += overlap(left.aliases, right.aliases) * 2; + value += overlap(left.alternatives ?? [], right.keywords) * 2; + + const manual = MANUAL_RELATIONS[left.id] ?? []; + if (manual.includes(right.id)) value += 20; + + const aliasManual = MANUAL_ALIASES[left.id] ?? []; + if (aliasManual.some((alias) => right.keywords.includes(alias))) value += 2; + + return value; +} + +async function build() { + const patterns = JSON.parse(await fs.readFile(patternsPath, "utf8")); + const relatedMap = {}; + + for (const pattern of patterns) { + const related = patterns + .filter((candidate) => candidate.id !== pattern.id) + .map((candidate) => ({ id: candidate.id, score: score(pattern, candidate) })) + .filter((candidate) => candidate.score > 0) + .sort((left, right) => right.score - left.score) + .slice(0, 4) + .map((candidate) => candidate.id); + + relatedMap[pattern.id] = related; + pattern.relatedPatternIds = related; + } + + await fs.writeFile(patternsPath, `${JSON.stringify(patterns, null, 2)}\n`, "utf8"); + await fs.writeFile(relatedOutput, `${JSON.stringify(relatedMap, null, 2)}\n`, "utf8"); +} + +await build(); diff --git a/site/scripts/extract-pattern-metadata.mjs b/site/scripts/extract-pattern-metadata.mjs new file mode 100644 index 0000000..37b11c6 --- /dev/null +++ b/site/scripts/extract-pattern-metadata.mjs @@ -0,0 +1,260 @@ +import MarkdownIt from "markdown-it"; +import matter from "gray-matter"; +import { + collectHeadings, + getFirstParagraph, + getH1, + linesToList, + normalizeHeading, + sectionContent, + stripMarkdown, + toTitleFromFolder, + uniqueNormalized, +} from "./markdown-utils.mjs"; + +const markdown = new MarkdownIt({ + html: true, + linkify: true, + typographer: true, +}); + +const CATEGORY_LABELS = { + gof: "GoF", + architectural: "Architectural", + "enterprise-integration": "Enterprise Integration", + reliability: "Reliability", + miscellaneous: "Miscellaneous", +}; + +const GOF_SUBCATEGORIES = { + "abstract-factory": "creational", + adapter: "structural", + bridge: "structural", + builder: "creational", + chain: "behavioral", + command: "behavioral", + composite: "structural", + decorator: "structural", + facade: "structural", + "factory-method": "creational", + flyweight: "structural", + interpreter: "behavioral", + iterator: "behavioral", + mediator: "behavioral", + memento: "behavioral", + observer: "behavioral", + prototype: "creational", + proxy: "structural", + singleton: "creational", + state: "behavioral", + strategy: "behavioral", + "template-method": "behavioral", + visitor: "behavioral", +}; + +const FEATURED_PATTERNS = new Set([ + "abstract-factory", + "observer", + "circuit-breaker", + "retry-backoff", + "saga", + "service-locator", +]); + +export const MANUAL_ALIASES = { + "abstract-factory": ["AF"], + "factory-method": ["FM"], + "double-checked-locking": ["DCL"], + nullobject: ["null object", "null-object"], + "retry-backoff": ["retry with backoff"], + filter: ["criteria", "criteria pattern"], + "model-view-presenter": ["MVP"], + cqrs: ["command query responsibility segregation"], +}; + +function deriveCategory(folder) { + if (folder === "gof-patterns") return "gof"; + if (folder === "architectural-patterns") return "architectural"; + if (folder === "enterprise-integration-patterns") return "enterprise-integration"; + if (folder === "reliability-patterns") return "reliability"; + return "miscellaneous"; +} + +function inferName(folderName, content) { + const h1 = getH1(content); + if (h1 && h1 !== "#") { + return h1.replace(/\s+Pattern$/i, "").trim(); + } + return toTitleFromFolder(folderName); +} + +function inferSummary(content, frontmatterSummary) { + if (typeof frontmatterSummary === "string" && frontmatterSummary.trim()) { + return frontmatterSummary.trim(); + } + + const firstParagraph = stripMarkdown(getFirstParagraph(content)); + return firstParagraph || "Runnable Java example with implementation notes and trade-offs."; +} + +function inferSubcategory(category, folderName, frontmatterSubcategory) { + if (typeof frontmatterSubcategory === "string" && frontmatterSubcategory.trim()) { + return frontmatterSubcategory.trim(); + } + if (category === "gof") { + return GOF_SUBCATEGORIES[folderName]; + } + return undefined; +} + +function inferAliases(folderName, name, frontmatterAliases) { + const aliases = [ + folderName.replace(/-/g, " "), + name, + ...(Array.isArray(frontmatterAliases) ? frontmatterAliases : []), + ...(MANUAL_ALIASES[folderName] ?? []), + ]; + + if (name.includes("&")) { + aliases.push(name.replace("&", "and")); + } + + return uniqueNormalized(aliases); +} + +function extractIntentProblemApplicability(content) { + const intent = stripMarkdown( + sectionContent(content, ["Intent", "When to use", "Overview"]), + ).slice(0, 420); + const problemSection = sectionContent(content, ["Problem", "Problem Solved"]); + const applicabilitySection = sectionContent(content, [ + "Applicability", + "Use When", + "When to use", + "When not to use", + ]); + + return { + intent: intent || undefined, + problem: stripMarkdown(problemSection).slice(0, 320) || undefined, + applicability: linesToList(applicabilitySection), + }; +} + +function extractTradeOffs(content) { + const tradeOffsSection = sectionContent(content, [ + "Trade-offs", + "Tradeoffs", + "Advantages", + "Disadvantages", + ]); + return linesToList(tradeOffsSection); +} + +function extractAlternatives(content) { + const alternativesSection = sectionContent(content, [ + "Alternatives", + "Alternatives & Similar Patterns", + "Related patterns", + "When NOT to Use", + ]); + return linesToList(alternativesSection); +} + +function deriveKeywords({ name, category, subcategory, aliases, tags, headings, summary, intent }) { + const seed = [ + name, + category, + subcategory ?? "", + ...aliases, + ...tags, + ...headings, + ...summary.split(/\W+/), + ...(intent ?? "").split(/\W+/), + ]; + + const domainKeywords = []; + const normalizedName = name.toLowerCase(); + if (normalizedName.includes("factory")) domainKeywords.push("object creation", "family of objects"); + if (normalizedName.includes("observer")) domainKeywords.push("event-driven", "pub-sub"); + if (normalizedName.includes("state")) domainKeywords.push("state transitions", "state-driven behavior"); + if (normalizedName.includes("breaker")) domainKeywords.push("resilience", "retry remote calls"); + if (normalizedName.includes("saga")) domainKeywords.push("message flow", "distributed transaction"); + + return uniqueNormalized( + [...seed, ...domainKeywords] + .map((value) => value.trim()) + .filter((value) => value.length > 2 && !/^\d+$/.test(value)), + ); +} + +function readingTimeMinutes(content) { + const words = stripMarkdown(content).split(/\s+/).filter(Boolean).length; + return Math.max(1, Math.ceil(words / 180)); +} + +export async function extractPatternMetadata({ + categoryFolder, + folderName, + repoPath, + githubUrl, + markdownSource, + hasTests, + demoCodePaths, +}) { + const parsed = matter(markdownSource); + const category = deriveCategory(categoryFolder); + const name = String(parsed.data.name || inferName(folderName, parsed.content)); + const summary = inferSummary(parsed.content, parsed.data.summary); + const subcategory = inferSubcategory(category, folderName, parsed.data.subcategory); + const aliases = inferAliases(folderName, name, parsed.data.aliases); + const headings = collectHeadings(parsed.content); + const tags = uniqueNormalized([ + ...(Array.isArray(parsed.data.tags) ? parsed.data.tags : []), + category, + subcategory ?? "", + ...headings.map((heading) => normalizeHeading(heading)), + ]); + const { intent, problem, applicability } = extractIntentProblemApplicability(parsed.content); + const tradeOffs = extractTradeOffs(parsed.content); + const alternatives = extractAlternatives(parsed.content); + const keywords = deriveKeywords({ + name, + category, + subcategory, + aliases, + tags, + headings, + summary, + intent, + }); + + return { + id: folderName, + slug: folderName, + name, + category, + subcategory, + summary, + intent, + problem, + applicability, + tradeOffs, + alternatives, + keywords, + aliases, + tags, + githubPath: repoPath, + githubUrl, + demoCodePaths, + hasTests, + readingTimeMinutes: readingTimeMinutes(parsed.content), + contentHtml: markdown.render(parsed.content), + contentMarkdown: parsed.content.trim(), + relatedPatternIds: [], + categoryLabel: CATEGORY_LABELS[category], + headingIndex: headings, + excerpt: stripMarkdown(parsed.content).slice(0, 260), + featured: FEATURED_PATTERNS.has(folderName), + }; +} diff --git a/site/scripts/markdown-utils.mjs b/site/scripts/markdown-utils.mjs new file mode 100644 index 0000000..76d5641 --- /dev/null +++ b/site/scripts/markdown-utils.mjs @@ -0,0 +1,144 @@ +export function stripMarkdown(markdown) { + return markdown + .replace(/^---[\s\S]*?---\s*/m, "") + .replace(/```[\s\S]*?```/g, " ") + .replace(/`([^`]+)`/g, "$1") + .replace(/!\[[^\]]*]\([^)]*\)/g, " ") + .replace(/\[([^\]]+)]\(([^)]+)\)/g, "$1") + .replace(/^#{1,6}\s+/gm, "") + .replace(/[*_>~-]/g, " ") + .replace(/\|/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +export function normalizeHeading(value) { + return value + .toLowerCase() + .replace(/[^\p{L}\p{N}\s/-]/gu, " ") + .replace(/\s+/g, " ") + .trim(); +} + +export function collectHeadings(markdown) { + return [...markdown.matchAll(/^##+\s+(.+)$/gm)].map((match) => match[1].trim()); +} + +export function getFirstParagraph(markdown) { + const lines = markdown + .replace(/^---[\s\S]*?---\s*/m, "") + .split("\n") + .map((line) => line.trim()); + + let current = []; + for (const line of lines) { + if (!line) { + if (current.length) { + break; + } + continue; + } + + if ( + line.startsWith("#") || + line.startsWith("```") || + line.startsWith("|") || + line === "---" + ) { + if (current.length) { + break; + } + continue; + } + + current.push(line); + } + + return current.join(" ").trim(); +} + +export function getH1(markdown) { + const matches = [...markdown.matchAll(/^#\s*(.*)$/gm)]; + for (const match of matches) { + const value = match[1]?.trim() ?? ""; + if (value && value !== "#") { + return value.replace(/^#\s*/, "").trim(); + } + } + return ""; +} + +export function toTitleFromFolder(folderName) { + return folderName + .split("-") + .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) + .join(" "); +} + +export function sectionContent(markdown, candidateHeadings) { + const headingSet = new Set(candidateHeadings.map(normalizeHeading)); + const lines = markdown.split("\n"); + let collecting = false; + const collected = []; + + for (const line of lines) { + const headingMatch = line.match(/^(##+)\s+(.+)$/); + if (headingMatch) { + const normalized = normalizeHeading(headingMatch[2]); + if (collecting) { + break; + } + if (headingSet.has(normalized)) { + collecting = true; + continue; + } + } + + if (collecting) { + collected.push(line); + } + } + + return collected.join("\n").trim(); +} + +export function linesToList(value) { + if (!value.trim()) { + return []; + } + + const bulletItems = value + .split("\n") + .map((line) => line.trim()) + .filter((line) => /^[-*]\s+/.test(line)) + .map((line) => line.replace(/^[-*]\s+/, "").trim()) + .filter(Boolean); + + if (bulletItems.length) { + return bulletItems; + } + + return stripMarkdown(value) + .split(/(?<=\.)\s+|;\s+/) + .map((item) => item.trim()) + .filter((item) => item.length > 12) + .slice(0, 5); +} + +export function uniqueNormalized(values) { + const seen = new Set(); + const result = []; + for (const value of values) { + const trimmed = value.trim(); + if (!trimmed) { + continue; + } + const key = trimmed.toLowerCase(); + if (seen.has(key)) { + continue; + } + seen.add(key); + result.push(trimmed); + } + return result; +} diff --git a/site/src/App.tsx b/site/src/App.tsx new file mode 100644 index 0000000..be0ce34 --- /dev/null +++ b/site/src/App.tsx @@ -0,0 +1,221 @@ +import { useDeferredValue, useEffect, useMemo, useState } from "react"; +import { Navigate, Route, Routes, useLocation, useNavigate, useParams } from "react-router-dom"; +import patternsUrl from "./content/patterns.json?url"; +import relatedUrl from "./content/related-patterns.json?url"; +import { AppShell } from "./components/layout/AppShell"; +import { SearchCommandPalette } from "./components/search/SearchCommandPalette"; +import { createPatternSearch } from "./lib/search"; +import { AboutPage } from "./pages/AboutPage"; +import { CatalogPage } from "./pages/CatalogPage"; +import { HomePage } from "./pages/HomePage"; +import { NotFoundPage } from "./pages/NotFoundPage"; +import { PatternPage } from "./pages/PatternPage"; +import type { PatternCategory, PatternRecord, RelatedPatternMap } from "./types/pattern"; + +function useRecentSearches() { + const [recentSearches, setRecentSearches] = useState([]); + + useEffect(() => { + const saved = window.localStorage.getItem("pattern-recent-searches"); + if (saved) { + setRecentSearches(JSON.parse(saved) as string[]); + } + }, []); + + const remember = (value: string) => { + if (!value.trim()) { + return; + } + const next = [value, ...recentSearches.filter((item) => item !== value)].slice(0, 6); + setRecentSearches(next); + window.localStorage.setItem("pattern-recent-searches", JSON.stringify(next)); + }; + + return { recentSearches, remember }; +} + +function useCatalogState() { + const location = useLocation(); + const navigate = useNavigate(); + const params = new URLSearchParams(location.search); + const query = params.get("q") ?? ""; + const categoryParam = params.get("category") as PatternCategory | null; + + const setQuery = (value: string, category = categoryParam ?? "all") => { + const nextParams = new URLSearchParams(); + if (value.trim()) nextParams.set("q", value); + if (category !== "all") nextParams.set("category", category); + navigate({ pathname: "/patterns", search: nextParams.toString() }, { replace: true }); + }; + + const setCategory = (value: PatternCategory | "all") => setQuery(query, value); + + return { + query, + category: categoryParam ?? "all", + setQuery, + setCategory, + }; +} + +function CatalogRoute(props: { patterns: PatternRecord[]; onOpenPalette: () => void }) { + const { patterns, onOpenPalette } = props; + const { query, category, setQuery, setCategory } = useCatalogState(); + const deferredQuery = useDeferredValue(query); + const search = useMemo(() => createPatternSearch(patterns), [patterns]); + + const filtered = useMemo(() => { + return search + .search(deferredQuery, category) + .map((entry) => entry.pattern); + }, [category, deferredQuery, search]); + + return ( + setQuery(value, category)} + onCategoryChange={setCategory} + onIntentClick={(value) => setQuery(value, category)} + onOpenPalette={onOpenPalette} + /> + ); +} + +function CategoryRoute(props: { patterns: PatternRecord[]; onOpenPalette: () => void }) { + const { categoryId } = useParams(); + const navigate = useNavigate(); + const category = (categoryId as PatternCategory | undefined) ?? "all"; + + useEffect(() => { + navigate({ pathname: "/patterns", search: category === "all" ? "" : `category=${category}` }, { replace: true }); + }, [category, navigate]); + + return ; +} + +function HomeRoute(props: { patterns: PatternRecord[]; onOpenPalette: () => void }) { + const { patterns, onOpenPalette } = props; + const [query, setQuery] = useState(""); + const deferredQuery = useDeferredValue(query); + const search = useMemo(() => createPatternSearch(patterns), [patterns]); + + const featuredPatterns = useMemo(() => { + if (deferredQuery.trim()) { + return search.search(deferredQuery).slice(0, 6).map((entry) => entry.pattern); + } + return patterns.filter((pattern) => pattern.featured).slice(0, 6); + }, [deferredQuery, patterns, search]); + + const testedPatterns = patterns.filter((pattern) => pattern.hasTests).length; + const examplesIncluded = patterns.reduce((sum, pattern) => sum + (pattern.demoCodePaths?.length ?? 0), 0); + const totalCategories = new Set(patterns.map((pattern) => pattern.category)).size; + + return ( + + ); +} + +function PatternRoute(props: { patterns: PatternRecord[]; relatedPatterns: RelatedPatternMap }) { + const { slug } = useParams(); + const pattern = props.patterns.find((item) => item.slug === slug); + if (!pattern) { + return ; + } + const related = (props.relatedPatterns[pattern.id] ?? []) + .map((id) => props.patterns.find((candidate) => candidate.id === id)) + .filter((item): item is PatternRecord => Boolean(item)); + return ; +} + +export default function App() { + const [patterns, setPatterns] = useState([]); + const [relatedPatterns, setRelatedPatterns] = useState({}); + const [isLoading, setIsLoading] = useState(true); + const [paletteOpen, setPaletteOpen] = useState(false); + const { recentSearches, remember } = useRecentSearches(); + + useEffect(() => { + let active = true; + + async function loadContent() { + try { + const [patternsResponse, relatedResponse] = await Promise.all([ + fetch(patternsUrl), + fetch(relatedUrl), + ]); + const [patternsPayload, relatedPayload] = await Promise.all([ + patternsResponse.json(), + relatedResponse.json(), + ]); + if (!active) return; + setPatterns(patternsPayload as PatternRecord[]); + setRelatedPatterns(relatedPayload as RelatedPatternMap); + } finally { + if (active) setIsLoading(false); + } + } + + void loadContent(); + return () => { + active = false; + }; + }, []); + + const search = useMemo(() => createPatternSearch(patterns), [patterns]); + + useEffect(() => { + const onKeyDown = (event: KeyboardEvent) => { + if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") { + event.preventDefault(); + setPaletteOpen(true); + } + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, []); + + return ( + setPaletteOpen(true)}> + setPaletteOpen(false)} + patterns={patterns} + recentSearches={recentSearches} + onRememberSearch={remember} + search={search} + /> + {isLoading ? ( +
+
Loading
+

Building the catalog view

+

Loading the generated pattern index and search sources.

+
+ ) : ( + + setPaletteOpen(true)} />} /> + setPaletteOpen(true)} />} /> + } /> + setPaletteOpen(true)} />} /> + } /> + } /> + } /> + + )} +
+ ); +} diff --git a/site/src/components/common/Button.tsx b/site/src/components/common/Button.tsx new file mode 100644 index 0000000..eabf7d3 --- /dev/null +++ b/site/src/components/common/Button.tsx @@ -0,0 +1,38 @@ +import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from "react"; + +interface SharedProps { + children: ReactNode; + variant?: "primary" | "secondary" | "ghost"; + className?: string; +} + +type Props = + | ({ href: string } & AnchorHTMLAttributes & SharedProps) + | ({ href?: undefined } & ButtonHTMLAttributes & SharedProps); + +const variants = { + primary: + "border border-cyan-400/30 bg-cyan-400/18 text-cyan-100 hover:border-cyan-300 hover:bg-cyan-400/28", + secondary: + "border border-white/14 bg-white/[0.04] text-slate-100 hover:border-white/28 hover:bg-white/[0.08]", + ghost: + "border border-transparent bg-transparent text-slate-200 hover:border-white/14 hover:bg-white/[0.05]", +}; + +export function Button({ children, className = "", variant = "primary", ...props }: Props) { + const classes = `inline-flex items-center justify-center rounded-full px-5 py-2.5 text-sm font-semibold transition focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-cyan-300 ${variants[variant]} ${className}`.trim(); + + if ("href" in props && props.href) { + return ( + + {children} + + ); + } + + return ( + + ); +} diff --git a/site/src/components/filters/CategoryFilterBar.tsx b/site/src/components/filters/CategoryFilterBar.tsx new file mode 100644 index 0000000..fc80a64 --- /dev/null +++ b/site/src/components/filters/CategoryFilterBar.tsx @@ -0,0 +1,39 @@ +import { categories } from "../../data/categories"; +import type { PatternCategory } from "../../types/pattern"; + +export function CategoryFilterBar(props: { + activeCategory: PatternCategory | "all"; + onChange: (value: PatternCategory | "all") => void; +}) { + const { activeCategory, onChange } = props; + + return ( +
+ + {categories.map((category) => ( + + ))} +
+ ); +} diff --git a/site/src/components/layout/AppShell.tsx b/site/src/components/layout/AppShell.tsx new file mode 100644 index 0000000..83db59a --- /dev/null +++ b/site/src/components/layout/AppShell.tsx @@ -0,0 +1,25 @@ +import type { ReactNode } from "react"; +import { Footer } from "./Footer"; +import { Header } from "./Header"; + +interface AppShellProps { + children: ReactNode; + onOpenSearch: () => void; +} + +export function AppShell({ children, onOpenSearch }: AppShellProps) { + return ( +
+ + Skip to content + +
+
+
{children}
+
+
+ ); +} diff --git a/site/src/components/layout/Footer.tsx b/site/src/components/layout/Footer.tsx new file mode 100644 index 0000000..cc60798 --- /dev/null +++ b/site/src/components/layout/Footer.tsx @@ -0,0 +1,25 @@ +import { contributionUrl, repositoryUrl } from "../../lib/github"; +import { Button } from "../common/Button"; + +export function Footer() { + return ( +
+
+
+
Found this useful?
+

+ The catalog is generated from the repository source folders. Star the repo, review the examples, or send a documentation improvement directly from the pattern page. +

+
+
+ + +
+
+
+ ); +} diff --git a/site/src/components/layout/Header.tsx b/site/src/components/layout/Header.tsx new file mode 100644 index 0000000..73fcaed --- /dev/null +++ b/site/src/components/layout/Header.tsx @@ -0,0 +1,110 @@ +import { useEffect, useState } from "react"; +import { Link, NavLink } from "react-router-dom"; +import { repositoryUrl } from "../../lib/github"; +import { Button } from "../common/Button"; + +interface HeaderProps { + onOpenSearch: () => void; +} + +export function Header({ onOpenSearch }: HeaderProps) { + const [isCompact, setIsCompact] = useState(false); + const [isMobileOpen, setIsMobileOpen] = useState(false); + + useEffect(() => { + const onScroll = () => setIsCompact(window.scrollY > 18); + onScroll(); + window.addEventListener("scroll", onScroll); + return () => window.removeEventListener("scroll", onScroll); + }, []); + + const links = [ + { to: "/", label: "Home" }, + { to: "/patterns", label: "Explore" }, + { to: "/categories/gof", label: "Categories" }, + { to: "/categories/reliability", label: "Reliability" }, + { to: "/about", label: "About" }, + ]; + + return ( +
+
+ + +
+
Pattern Hex
+
Practical Java Design Patterns
+
+ + + + + +
+ + {isMobileOpen ? ( +
+ +
+ ) : null} +
+ ); +} diff --git a/site/src/components/patterns/CategoryBadge.tsx b/site/src/components/patterns/CategoryBadge.tsx new file mode 100644 index 0000000..026d515 --- /dev/null +++ b/site/src/components/patterns/CategoryBadge.tsx @@ -0,0 +1,10 @@ +import { categoryMap } from "../../data/categories"; +import type { PatternCategory } from "../../types/pattern"; + +export function CategoryBadge({ category }: { category: PatternCategory }) { + return ( + + {categoryMap[category].label} + + ); +} diff --git a/site/src/components/patterns/PatternCard.tsx b/site/src/components/patterns/PatternCard.tsx new file mode 100644 index 0000000..365ef49 --- /dev/null +++ b/site/src/components/patterns/PatternCard.tsx @@ -0,0 +1,51 @@ +import { Link } from "react-router-dom"; +import type { PatternRecord } from "../../types/pattern"; +import { HighlightedText } from "../search/HighlightedText"; +import { CategoryBadge } from "./CategoryBadge"; + +interface PatternCardProps { + pattern: PatternRecord; + query: string; +} + +export function PatternCard({ pattern, query }: PatternCardProps) { + return ( +
+
+ + {pattern.subcategory ? ( + {pattern.subcategory} + ) : null} +
+

+ +

+

+ +

+
+ {pattern.tags.slice(0, 4).map((tag) => ( + + {tag} + + ))} +
+
+ + View details + + + View on GitHub + +
+
+ ); +} diff --git a/site/src/components/patterns/RelatedPatterns.tsx b/site/src/components/patterns/RelatedPatterns.tsx new file mode 100644 index 0000000..adba5ee --- /dev/null +++ b/site/src/components/patterns/RelatedPatterns.tsx @@ -0,0 +1,26 @@ +import { Link } from "react-router-dom"; +import type { PatternRecord } from "../../types/pattern"; + +export function RelatedPatterns({ items }: { items: PatternRecord[] }) { + if (!items.length) { + return null; + } + + return ( +
+
You may also want
+
+ {items.map((item) => ( + +
{item.name}
+
{item.summary}
+ + ))} +
+
+ ); +} diff --git a/site/src/components/search/HighlightedText.tsx b/site/src/components/search/HighlightedText.tsx new file mode 100644 index 0000000..bcf40ac --- /dev/null +++ b/site/src/components/search/HighlightedText.tsx @@ -0,0 +1,26 @@ +interface HighlightedTextProps { + text: string; + query: string; +} + +export function HighlightedText({ text, query }: HighlightedTextProps) { + const trimmed = query.trim(); + if (!trimmed) { + return <>{text}; + } + + const pattern = new RegExp(`(${trimmed.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`, "ig"); + return ( + <> + {text.split(pattern).map((part, index) => + part.toLowerCase() === trimmed.toLowerCase() ? ( + + {part} + + ) : ( + {part} + ), + )} + + ); +} diff --git a/site/src/components/search/SearchBar.tsx b/site/src/components/search/SearchBar.tsx new file mode 100644 index 0000000..8001dd1 --- /dev/null +++ b/site/src/components/search/SearchBar.tsx @@ -0,0 +1,31 @@ +interface SearchBarProps { + query: string; + onQueryChange: (value: string) => void; + onOpenPalette?: () => void; +} + +export function SearchBar({ query, onQueryChange, onOpenPalette }: SearchBarProps) { + return ( +
+ +
+ ); +} diff --git a/site/src/components/search/SearchCommandPalette.tsx b/site/src/components/search/SearchCommandPalette.tsx new file mode 100644 index 0000000..58b659a --- /dev/null +++ b/site/src/components/search/SearchCommandPalette.tsx @@ -0,0 +1,173 @@ +import { useDeferredValue, useEffect, useMemo, useRef, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import type { PatternRecord } from "../../types/pattern"; +import { Button } from "../common/Button"; + +interface SearchCommandPaletteProps { + isOpen: boolean; + onClose: () => void; + patterns: PatternRecord[]; + recentSearches: string[]; + onRememberSearch: (value: string) => void; + search: { + search: (query: string) => { pattern: PatternRecord; score: number }[]; + suggestions: (query: string) => string[]; + }; +} + +export function SearchCommandPalette(props: SearchCommandPaletteProps) { + const { isOpen, onClose, patterns, recentSearches, onRememberSearch, search } = props; + const [query, setQuery] = useState(""); + const [activeIndex, setActiveIndex] = useState(0); + const inputRef = useRef(null); + const navigate = useNavigate(); + const deferredQuery = useDeferredValue(query); + + const results = useMemo(() => { + const entries = deferredQuery.trim() + ? search.search(deferredQuery).slice(0, 8) + : patterns + .filter((pattern) => pattern.featured) + .slice(0, 8) + .map((pattern, index) => ({ pattern, score: 100 - index })); + return entries; + }, [deferredQuery, patterns, search]); + + const suggestions = useMemo(() => search.suggestions(deferredQuery), [deferredQuery, search]); + + useEffect(() => { + if (!isOpen) { + setQuery(""); + setActiveIndex(0); + return; + } + inputRef.current?.focus(); + }, [isOpen]); + + useEffect(() => { + setActiveIndex(0); + }, [deferredQuery]); + + useEffect(() => { + if (!isOpen) { + return; + } + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + onClose(); + return; + } + if (event.key === "ArrowDown") { + event.preventDefault(); + setActiveIndex((value) => Math.min(value + 1, Math.max(results.length - 1, 0))); + } + if (event.key === "ArrowUp") { + event.preventDefault(); + setActiveIndex((value) => Math.max(value - 1, 0)); + } + if (event.key === "Enter" && results[activeIndex]) { + event.preventDefault(); + onRememberSearch(query.trim()); + navigate(`/patterns/${results[activeIndex].pattern.slug}`); + onClose(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [activeIndex, navigate, onClose, onRememberSearch, query, results, isOpen]); + + if (!isOpen) { + return null; + } + + return ( +
+
+
+ setQuery(event.target.value)} + className="w-full bg-transparent text-lg text-slate-50 outline-none placeholder:text-slate-500" + placeholder="Search patterns, use cases, aliases, or topics..." + aria-label="Search patterns" + /> +
+ +
+
+
Results
+
+ {results.map((entry, index) => ( + + ))} +
+
+ +
+
+
Suggestions
+
+ {suggestions.map((suggestion) => ( + + ))} +
+
+ +
+
Recent searches
+
+ {recentSearches.length ? ( + recentSearches.map((item) => ( + + )) + ) : ( +

No recent searches yet.

+ )} +
+
+
+
+
+
+ ); +} diff --git a/site/src/components/search/SearchResults.tsx b/site/src/components/search/SearchResults.tsx new file mode 100644 index 0000000..019ad6d --- /dev/null +++ b/site/src/components/search/SearchResults.tsx @@ -0,0 +1,44 @@ +import type { PatternRecord } from "../../types/pattern"; +import { intentChips } from "../../lib/search"; +import { PatternCard } from "../patterns/PatternCard"; + +export function SearchResults(props: { + patterns: PatternRecord[]; + query: string; + onSuggestionClick?: (value: string) => void; +}) { + const { patterns, query, onSuggestionClick } = props; + + if (!patterns.length) { + return ( +
+
No exact matches
+

+ Try a broader term, switch categories, or jump to one of these search prompts. +

+ {onSuggestionClick ? ( +
+ {intentChips.map((chip) => ( + + ))} +
+ ) : null} +
+ ); + } + + return ( +
+ {patterns.map((pattern) => ( + + ))} +
+ ); +} diff --git a/site/src/content/patterns.json b/site/src/content/patterns.json new file mode 100644 index 0000000..7321ff8 --- /dev/null +++ b/site/src/content/patterns.json @@ -0,0 +1,4784 @@ +[ + { + "id": "abstract-factory", + "slug": "abstract-factory", + "name": "Abstract Factory", + "category": "gof", + "subcategory": "creational", + "summary": "The Abstract Factory pattern Provides an interface for creating families of related or dependent objects without specifying their concrete classes.", + "intent": "The Abstract Factory pattern Provides an interface for creating families of related or dependent objects without specifying their concrete classes.", + "applicability": [ + "When simpler solutions suffice", + "When adding unnecessary complexity", + "In performance-critical paths (if it introduces overhead)" + ], + "tradeOffs": [], + "alternatives": [ + "When simpler solutions suffice", + "When adding unnecessary complexity", + "In performance-critical paths (if it introduces overhead)" + ], + "keywords": [ + "Abstract Factory", + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "related patterns", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References", + "The", + "Abstract", + "Factory", + "pattern", + "Provides", + "interface", + "for", + "creating", + "families", + "related", + "dependent", + "objects", + "without", + "specifying", + "their", + "concrete", + "classes", + "object creation", + "family of objects" + ], + "aliases": [ + "abstract factory", + "AF" + ], + "tags": [ + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "related patterns", + "references" + ], + "githubPath": "gof-patterns/abstract-factory", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/abstract-factory", + "demoCodePaths": [ + "gof-patterns/abstract-factory/src/main/java", + "gof-patterns/abstract-factory/src/main", + "gof-patterns/abstract-factory/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Abstract Factory Pattern

\n

📋 Overview

\n

The Abstract Factory pattern - Provides an interface for creating families of related or dependent objects without specifying their concrete classes.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • You need to create families of related objects while ensuring they work together correctly; switch between families without modifying client code.
  • \n
\n

Use When:

\n
    \n
  • Your system needs multiple families of related products
  • \n
  • Ensure only compatible family members are used
  • \n
  • Switch between product families dynamically
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
AbstractFactoryInterface for creating products
ConcreteFactoryImplements product creation
AbstractProductProduct interface
ConcreteProductConcrete implementations
\n
\n

💡 Code Example

\n
// Abstract Factory\npublic interface KingdomFactory {\n    Castle createCastle();\n    King createKing();\n    Army createArmy();\n}\n\n// Concrete Factories\npublic class ElfKingdomFactory implements KingdomFactory {\n    public Castle createCastle() { return new ElfCastle(); }\n    public King createKing() { return new ElfKing(); }\n    public Army createArmy() { return new ElfArmy(); }\n}\n\npublic class DwarfKingdomFactory implements KingdomFactory {\n    public Castle createCastle() { return new DwarfCastle(); }\n    public King createKing() { return new DwarfKing(); }\n    public Army createArmy() { return new DwarfArmy(); }\n}\n\n// Usage\nKingdomFactory factory = new ElfKingdomFactory();\nCastle castle = factory.createCastle();\n
\n

Reasoning: Client code doesn’t know concrete classes. Entire family changes by swapping factory. Ensures type-safe product combinations.

\n
\n

🔀 Design Principles

\n
    \n
  • Dependency Inversion
  • \n
  • Single Responsibility
  • \n
  • Open/Closed Principle
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class AbstractFactory {\n        <<interface>>\n        +createProductA()\n        +createProductB()\n    }\n    class ConcreteFactory1\n    class ConcreteFactory2\n    class AbstractProductA {\n        <<interface>>\n    }\n    class AbstractProductB {\n        <<interface>>\n    }\n    class ProductA1\n    class ProductA2\n    class ProductB1\n    class ProductB2\n    AbstractFactory <|-- ConcreteFactory1\n    AbstractFactory <|-- ConcreteFactory2\n    AbstractProductA <|-- ProductA1\n    AbstractProductA <|-- ProductA2\n    AbstractProductB <|-- ProductB1\n    AbstractProductB <|-- ProductB2\n    ConcreteFactory1 --> ProductA1\n    ConcreteFactory1 --> ProductB1\n    ConcreteFactory2 --> ProductA2\n    ConcreteFactory2 --> ProductB2\n    AbstractFactory --> AbstractProductA\n    AbstractFactory --> AbstractProductB\n    Client --> AbstractFactory\n    Client --> AbstractProductA\n    Client --> AbstractProductB\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>AbstractFactory: createProductA()\n    AbstractFactory-->>Client: AbstractProductA\n    Client->>AbstractFactory: createProductB()\n    AbstractFactory-->>Client: AbstractProductB\n    Client->>AbstractProductA: use()\n    Client->>AbstractProductB: use()\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Isolates client from concrete classes
  • \n
  • Ensures consistency among related products
  • \n
  • Easy to swap product families
  • \n
  • Centralizes product creation logic
  • \n
\n

Disadvantages ❌

\n
    \n
  • More interfaces/classes required
  • \n
  • Complex hierarchy
  • \n
  • Adding new product type affects all factories
  • \n
  • Overkill for simple scenarios
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • When simpler solutions suffice
  • \n
  • When adding unnecessary complexity
  • \n
  • In performance-critical paths (if it introduces overhead)
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
Factory returns nulluse OptionalUse appropriate implementation
Leaky abstractionsstick to interfacesUse appropriate implementation
Single Responsibility violationseparate concernsUse appropriate implementation
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Swing/AWT UI frameworks
  • \n
  • Database drivers (MySQL, Postgres)
  • \n
  • Cross-platform theme factories
  • \n
  • Java Collections framework factories
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AlternativeWhen to Use
Factory MethodWhen…
BuilderWhen…
PrototypeWhen…
\n
\n

📝 Best Practices

\n
    \n
  1. Keep the pattern simple and focused
  2. \n
  3. Document pattern usage in code
  4. \n
  5. Avoid overusing patterns
  6. \n
  7. Test pattern implementations thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Make patterns explicit in architecture
  12. \n
  13. Provide clear examples
  14. \n
  15. Review patterns periodically
  16. \n
\n
\n

🎓 Related Patterns

\n
    \n
  • Gang of Four patterns
  • \n
  • Enterprise Integration Patterns
  • \n
  • Architectural Patterns
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru Design Patterns
  • \n
\n", + "contentMarkdown": "# Abstract Factory Pattern\n\n## 📋 Overview\n\nThe **Abstract Factory** pattern - Provides an interface for creating families of related or dependent objects without specifying their concrete classes.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n\n- You need to create families of related objects while ensuring they work together correctly; switch between families without modifying client code.\n\n**Use When:**\n\n- Your system needs multiple families of related products\n- Ensure only compatible family members are used\n- Switch between product families dynamically\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| AbstractFactory | Interface for creating products |\n| ConcreteFactory | Implements product creation |\n| AbstractProduct | Product interface |\n| ConcreteProduct | Concrete implementations |\n\n---\n\n## 💡 Code Example\n\n```java\n// Abstract Factory\npublic interface KingdomFactory {\n Castle createCastle();\n King createKing();\n Army createArmy();\n}\n\n// Concrete Factories\npublic class ElfKingdomFactory implements KingdomFactory {\n public Castle createCastle() { return new ElfCastle(); }\n public King createKing() { return new ElfKing(); }\n public Army createArmy() { return new ElfArmy(); }\n}\n\npublic class DwarfKingdomFactory implements KingdomFactory {\n public Castle createCastle() { return new DwarfCastle(); }\n public King createKing() { return new DwarfKing(); }\n public Army createArmy() { return new DwarfArmy(); }\n}\n\n// Usage\nKingdomFactory factory = new ElfKingdomFactory();\nCastle castle = factory.createCastle();\n```\n\n**Reasoning:** Client code doesn't know concrete classes. Entire family changes by swapping factory. Ensures type-safe product combinations.\n\n---\n\n## 🔀 Design Principles\n\n- **Dependency Inversion**\n- **Single Responsibility**\n- **Open/Closed Principle**\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class AbstractFactory {\n <>\n +createProductA()\n +createProductB()\n }\n class ConcreteFactory1\n class ConcreteFactory2\n class AbstractProductA {\n <>\n }\n class AbstractProductB {\n <>\n }\n class ProductA1\n class ProductA2\n class ProductB1\n class ProductB2\n AbstractFactory <|-- ConcreteFactory1\n AbstractFactory <|-- ConcreteFactory2\n AbstractProductA <|-- ProductA1\n AbstractProductA <|-- ProductA2\n AbstractProductB <|-- ProductB1\n AbstractProductB <|-- ProductB2\n ConcreteFactory1 --> ProductA1\n ConcreteFactory1 --> ProductB1\n ConcreteFactory2 --> ProductA2\n ConcreteFactory2 --> ProductB2\n AbstractFactory --> AbstractProductA\n AbstractFactory --> AbstractProductB\n Client --> AbstractFactory\n Client --> AbstractProductA\n Client --> AbstractProductB\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>AbstractFactory: createProductA()\n AbstractFactory-->>Client: AbstractProductA\n Client->>AbstractFactory: createProductB()\n AbstractFactory-->>Client: AbstractProductB\n Client->>AbstractProductA: use()\n Client->>AbstractProductB: use()\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n\n- Isolates client from concrete classes\n- Ensures consistency among related products\n- Easy to swap product families\n- Centralizes product creation logic\n\n### Disadvantages ❌\n\n- More interfaces/classes required\n- Complex hierarchy\n- Adding new product type affects all factories\n- Overkill for simple scenarios\n\n---\n\n## 🚫 When NOT to Use\n\n- When simpler solutions suffice\n- When adding unnecessary complexity\n- In performance-critical paths (if it introduces overhead)\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Factory returns null | use Optional | Use appropriate implementation |\n| Leaky abstractions | stick to interfaces | Use appropriate implementation |\n| Single Responsibility violation | separate concerns | Use appropriate implementation |\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Swing/AWT UI frameworks\n- Database drivers (MySQL, Postgres)\n- Cross-platform theme factories\n- Java Collections framework factories\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n| Alternative | When to Use |\n|-------------|------------|\n| Factory Method | When... |\n| Builder | When... |\n| Prototype | When... |\n\n---\n\n## 📝 Best Practices\n\n1. Keep the pattern simple and focused\n2. Document pattern usage in code\n3. Avoid overusing patterns\n4. Test pattern implementations thoroughly\n5. Consider performance implications\n6. Make patterns explicit in architecture\n7. Provide clear examples\n8. Review patterns periodically\n\n---\n\n## 🎓 Related Patterns\n\n- Gang of Four patterns\n- Enterprise Integration Patterns\n- Architectural Patterns\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru Design Patterns", + "relatedPatternIds": [ + "factory-method", + "prototype", + "builder", + "singleton" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References" + ], + "excerpt": "Abstract Factory Pattern 📋 Overview The Abstract Factory pattern Provides an interface for creating families of related or dependent objects without specifying their concrete classes. 👥 Roles & Responsibilities Role Responsibility AbstractFactory Interface f", + "featured": true + }, + { + "id": "adapter", + "slug": "adapter", + "name": "Adapter", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Adapter design pattern implementation.", + "intent": "This folder contains the Adapter design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Adapter", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "adapter" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/adapter", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/adapter", + "demoCodePaths": [ + "gof-patterns/adapter/src/main/java", + "gof-patterns/adapter/src/main", + "gof-patterns/adapter/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Adapter Pattern

\n

📋 Overview

\n

This folder contains the Adapter design pattern implementation.

\n
\n

🎯 Intent

\n

The adapter pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Target {\n        <<interface>>\n        +request()\n    }\n    class Adapter {\n        +request()\n    }\n    class Adaptee {\n        +specificRequest()\n    }\n    Client --> Target\n    Target <|-- Adapter\n    Adapter --> Adaptee\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Target: request()\n    Target->>Adapter: request()\n    Adapter->>Adaptee: specificRequest()\n    Adaptee-->>Adapter: result\n    Adapter-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Adapter Pattern\n\n## 📋 Overview\n\nThis folder contains the **Adapter** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe adapter pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Target {\n <>\n +request()\n }\n class Adapter {\n +request()\n }\n class Adaptee {\n +specificRequest()\n }\n Client --> Target\n Target <|-- Adapter\n Adapter --> Adaptee\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Target: request()\n Target->>Adapter: request()\n Adapter->>Adaptee: specificRequest()\n Adaptee-->>Adapter: result\n Adapter-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "bridge", + "composite", + "decorator", + "facade" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Adapter Pattern 📋 Overview This folder contains the Adapter design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the src/", + "featured": false + }, + { + "id": "bridge", + "slug": "bridge", + "name": "Bridge", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Bridge design pattern implementation.", + "intent": "This folder contains the Bridge design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Bridge", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "bridge" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/bridge", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/bridge", + "demoCodePaths": [ + "gof-patterns/bridge/src/main/java", + "gof-patterns/bridge/src/main", + "gof-patterns/bridge/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Bridge Pattern

\n

📋 Overview

\n

This folder contains the Bridge design pattern implementation.

\n
\n

🎯 Intent

\n

The bridge pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Abstraction {\n        -implementor: Implementor\n        +operation()\n    }\n    class RefinedAbstraction\n    class Implementor {\n        <<interface>>\n        +operationImpl()\n    }\n    class ConcreteImplementorA\n    class ConcreteImplementorB\n    Client --> Abstraction\n    Abstraction <|-- RefinedAbstraction\n    Implementor <|-- ConcreteImplementorA\n    Implementor <|-- ConcreteImplementorB\n    Abstraction --> Implementor\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Abstraction: operation()\n    Abstraction->>Implementor: operationImpl()\n    Implementor-->>Abstraction: result\n    Abstraction-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Bridge Pattern\n\n## 📋 Overview\n\nThis folder contains the **Bridge** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe bridge pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Abstraction {\n -implementor: Implementor\n +operation()\n }\n class RefinedAbstraction\n class Implementor {\n <>\n +operationImpl()\n }\n class ConcreteImplementorA\n class ConcreteImplementorB\n Client --> Abstraction\n Abstraction <|-- RefinedAbstraction\n Implementor <|-- ConcreteImplementorA\n Implementor <|-- ConcreteImplementorB\n Abstraction --> Implementor\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Abstraction: operation()\n Abstraction->>Implementor: operationImpl()\n Implementor-->>Abstraction: result\n Abstraction-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "composite", + "decorator", + "facade" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Bridge Pattern 📋 Overview This folder contains the Bridge design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the src/ d", + "featured": false + }, + { + "id": "builder", + "slug": "builder", + "name": "Builder", + "category": "gof", + "subcategory": "creational", + "summary": "The Builder Pattern is a creational pattern that constructs complex objects step by step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional parameters or complex initialization logic.", + "intent": "The Builder Pattern is a creational pattern that constructs complex objects step by step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional parameters or complex initialization logic.", + "applicability": [ + "Scenario Why Avoid Simple Objects Objects with 1 2 parameters", + "use direct constructors Mutable Objects Builder is designed for immutability", + "doesn't benefit mutable objects Performance Critical Memory overhead of builder may matter in high frequency scenarios All Parameters Optional If no mandatory parameters, builder doesn't enforce constraints Frequent Modification If object needs modification after creation, use setters instead" + ], + "tradeOffs": [], + "alternatives": [ + "Scenario Why Avoid Simple Objects Objects with 1 2 parameters", + "use direct constructors Mutable Objects Builder is designed for immutability", + "doesn't benefit mutable objects Performance Critical Memory overhead of builder may matter in high frequency scenarios All Parameters Optional If no mandatory parameters, builder doesn't enforce constraints Frequent Modification If object needs modification after creation, use setters instead" + ], + "keywords": [ + "Builder", + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "implementation example", + "class diagram", + "sequence diagram", + "design principles emphasized", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns misuses", + "real-world use cases", + "java stringbuilder", + "google guava - immutablelist", + "lombok builder", + "http clients okhttp", + "apache commons - configuration", + "alternatives similar patterns", + "best practices", + "related patterns", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🔀 Design Principles Emphasized", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns & Misuses", + "🌍 Real-World Use Cases", + "Lombok @Builder", + "HTTP Clients (OkHttp)", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References", + "The", + "Pattern", + "that", + "constructs", + "complex", + "objects", + "step", + "separating", + "construction", + "logic", + "from", + "representation", + "provides", + "fluent", + "readable", + "interface", + "for", + "building", + "with", + "many", + "optional", + "parameters", + "initialization" + ], + "aliases": [ + "builder" + ], + "tags": [ + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "implementation example", + "class diagram", + "sequence diagram", + "design principles emphasized", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns misuses", + "real-world use cases", + "java stringbuilder", + "google guava - immutablelist", + "lombok builder", + "http clients okhttp", + "apache commons - configuration", + "alternatives similar patterns", + "best practices", + "related patterns", + "references" + ], + "githubPath": "gof-patterns/builder", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/builder", + "demoCodePaths": [ + "gof-patterns/builder/src/main/java", + "gof-patterns/builder/src/main", + "gof-patterns/builder/src" + ], + "hasTests": true, + "readingTimeMinutes": 4, + "contentHtml": "

Builder Pattern

\n

📋 Overview

\n

The Builder Pattern is a creational pattern that constructs complex objects step-by-step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional parameters or complex initialization logic.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Creating objects with many parameters is error-prone and produces unreadable code
  • \n
  • Objects have optional and mandatory parameters; telescoping constructors become unwieldy
  • \n
  • Complex initialization logic should be separated from object representation
  • \n
  • You need to construct immutable objects while maintaining readability
  • \n
\n

Use When:

\n
    \n
  • Objects have 3+ optional parameters
  • \n
  • You need to build immutable objects with validation
  • \n
  • Construction logic is complex or multi-step
  • \n
  • You want to improve code readability over constructor overloading
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ProductThe complex object being constructed (e.g., Hero)
BuilderAbstract interface defining construction steps
Concrete BuilderImplements construction steps, accumulates result
Director(Optional) Orchestrates the builder to construct products in a specific order
ClientUses builder to construct products
\n

Key Characteristics:

\n
    \n
  • Fluent interface enabling method chaining
  • \n
  • Separation of construction from representation
  • \n
  • Step-by-step object assembly
  • \n
  • Validation at build stage
  • \n
\n
\n

💡 Implementation Example

\n
// Product: Complex object to build\npublic class Hero {\n    private final String name;\n    private final Profession profession;\n    private final HairType hairType;\n    private final HairColor hairColor;\n    private final Armor armor;\n    private final Weapon weapon;\n\n    private Hero(HeroBuilder builder) {\n        this.name = builder.name;\n        this.profession = builder.profession;\n        this.hairType = builder.hairType;\n        this.hairColor = builder.hairColor;\n        this.armor = builder.armor;\n        this.weapon = builder.weapon;\n    }\n\n    // Builder: Inner class managing construction\n    public static class HeroBuilder {\n        private final String name;\n        private final Profession profession;\n        private HairType hairType;\n        private HairColor hairColor;\n        private Armor armor;\n        private Weapon weapon;\n\n        // Mandatory parameters in constructor\n        public HeroBuilder(Profession profession, String name) {\n            this.profession = profession;\n            this.name = name;\n        }\n\n        // Fluent methods for optional parameters\n        public HeroBuilder withHairType(HairType hairType) {\n            this.hairType = hairType;\n            return this;\n        }\n\n        public HeroBuilder withHairColor(HairColor hairColor) {\n            this.hairColor = hairColor;\n            return this;\n        }\n\n        public HeroBuilder withArmor(Armor armor) {\n            this.armor = armor;\n            return this;\n        }\n\n        public HeroBuilder withWeapon(Weapon weapon) {\n            this.weapon = weapon;\n            return this;\n        }\n\n        // Build: Final step returning the constructed product\n        public Hero build() {\n            return new Hero(this);\n        }\n    }\n}\n\n// Usage: Clean, readable, chainable construction\nHero mage = new Hero.HeroBuilder(Profession.MAGE, "Merlin")\n    .withHairColor(HairColor.BLACK)\n    .withWeapon(Weapon.STAFF)\n    .build();\n
\n

Reasoning:

\n
    \n
  • Separates object construction from its representation
  • \n
  • Fluent interface improves readability dramatically
  • \n
  • Mandatory parameters enforced in constructor
  • \n
  • Optional parameters via fluent methods
  • \n
  • Immutability achieved through private constructor
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Director {\n        -builder: Builder\n        +construct()\n    }\n    class Builder {\n        <<interface>>\n        +buildPartA()\n        +buildPartB()\n        +getResult()\n    }\n    class ConcreteBuilder\n    class Product\n    Client --> Director\n    Director --> Builder\n    Builder <|-- ConcreteBuilder\n    ConcreteBuilder --> Product\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Director: construct()\n    Director->>Builder: buildPartA()\n    Director->>Builder: buildPartB()\n    Builder-->>Director: done\n    Client->>Builder: getResult()\n    Builder-->>Client: Product\n
\n
\n

🔀 Design Principles Emphasized

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
PrincipleHow Applied
Single ResponsibilityBuilder manages construction; Product manages data
Separation of ConcernsObject representation separated from construction logic
Composition over InheritanceBuilder uses composition to accumulate object state
Fluent InterfaceMethod chaining improves readability
ImmutabilityConstructor is private; object state set via builder
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Improved Readability: Fluent interface makes code self-documenting
  • \n
  • Flexibility: Easy to add/remove optional parameters without breaking code
  • \n
  • Immutability: Separating construction enables creation of immutable objects
  • \n
  • Complex Initialization: Handles multi-step construction elegantly
  • \n
  • Mandatory Parameter Enforcement: Constructor ensures required params are present
  • \n
  • Validation: Can validate at build stage before creating object
  • \n
\n

Disadvantages ❌

\n
    \n
  • Code Verbosity: More classes and methods to maintain
  • \n
  • Performance Overhead: Creating builder object adds memory/GC pressure
  • \n
  • Complexity for Simple Objects: Overkill for objects with few parameters
  • \n
  • Thread Safety: Builder itself is not thread-safe; don’t share across threads
  • \n
  • Builder Proliferation: Every complex class needs its own builder
  • \n
\n
\n

🚫 When NOT to Use

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ScenarioWhy Avoid
Simple ObjectsObjects with 1-2 parameters; use direct constructors
Mutable ObjectsBuilder is designed for immutability; doesn’t benefit mutable objects
Performance CriticalMemory overhead of builder may matter in high-frequency scenarios
All Parameters OptionalIf no mandatory parameters, builder doesn’t enforce constraints
Frequent ModificationIf object needs modification after creation, use setters instead
\n
\n

⚠️ Common Anti-Patterns & Misuses

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternProblemSolution
Shared Builder Across ThreadsRace conditions when building concurrent productsCreate new builder per thread; builders not thread-safe
Builder Without ValidationInvalid objects created if validation deferredImplement validation in build() method
All-Optional BuilderNo constraints on required parametersEnforce mandatory params in builder constructor
Complex DirectorsDirector hides builder complexity instead of simplifying itDirector should orchestrate, not complicate
Mutable Product After BuildProduct state modified after construction defeats builder purposeKeep product immutable; add new builder if changes needed
Builder with SettersContradicts immutability goalUse only fluent builder methods, no setters on product
\n
\n

🌍 Real-World Use Cases

\n

Java StringBuilder

\n
// StringBuilder is a builder for immutable String\nString text = new StringBuilder()\n    .append("Hello")\n    .append(" ")\n    .append("World")\n    .toString();\n
\n

Google Guava - ImmutableList

\n
// Guava uses builder for complex immutable collections\nImmutableList<String> list = ImmutableList.builder()\n    .add("item1")\n    .add("item2")\n    .build();\n
\n

Lombok @Builder

\n
// Lombok annotation auto-generates builder\n@Builder\npublic class User {\n    private String name;\n    private String email;\n    private int age;\n}\n\n// Usage\nUser user = User.builder()\n    .name("Alice")\n    .email("alice@example.com")\n    .age(30)\n    .build();\n
\n

HTTP Clients (OkHttp)

\n
// OkHttp Request builder\nRequest request = new Request.Builder()\n    .url("https://example.com")\n    .addHeader("User-Agent", "MyApp")\n    .post(body)\n    .build();\n
\n

Apache Commons - Configuration

\n
// Configuration builder with fluent interface\nConfiguration config = new Configuration.Builder()\n    .setDatabaseUrl("jdbc:mysql://localhost")\n    .setMaxConnections(50)\n    .setReadTimeout(5000)\n    .build();\n
\n
\n

🔗 Alternatives & Similar Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AlternativeWhen to Prefer
Telescoping ConstructorFor simple objects with few parameters
JavaBeans with SettersWhen mutability is acceptable; not ideal for immutability
Factory MethodFor creating simple objects or choosing implementations
Abstract FactoryWhen building families of related objects
Fluent ConfigurationLightweight alternative to builder for configuration objects
\n
\n

📝 Best Practices

\n
    \n
  1. Enforce Mandatory Parameters: Place required params in builder constructor
  2. \n
  3. Use Method Chaining: Return this for fluent interface
  4. \n
  5. Validate in Build: Check constraints before creating product
  6. \n
  7. Keep Builder Simple: Avoid complex logic; delegate to product
  8. \n
  9. Consider Lombok: Use @Builder annotation to auto-generate builder code
  10. \n
  11. Make Product Immutable: Private constructor, final fields
  12. \n
  13. Document Optional Parameters: Clarify defaults and constraints
  14. \n
  15. Provide Copy Constructor: Allow building new instance from existing product
  16. \n
\n
\n

🎓 Related Patterns

\n
    \n
  • Factory Pattern: Can be used within builder to create complex sub-objects
  • \n
  • Composite Pattern: Builder often used to construct composite structures
  • \n
  • Strategy Pattern: Builder can use different strategies for object construction
  • \n
  • Template Method: Builder steps can follow a template structure
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch) - Item 2: Builder Pattern
  • \n
  • Google Guava Library
  • \n
  • Lombok @Builder Annotation
  • \n
\n", + "contentMarkdown": "# Builder Pattern\n\n## 📋 Overview\n\nThe **Builder Pattern** is a creational pattern that constructs complex objects step-by-step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional parameters or complex initialization logic.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Creating objects with many parameters is error-prone and produces unreadable code\n- Objects have optional and mandatory parameters; telescoping constructors become unwieldy\n- Complex initialization logic should be separated from object representation\n- You need to construct immutable objects while maintaining readability\n\n**Use When:**\n- Objects have 3+ optional parameters\n- You need to build immutable objects with validation\n- Construction logic is complex or multi-step\n- You want to improve code readability over constructor overloading\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| **Product** | The complex object being constructed (e.g., Hero) |\n| **Builder** | Abstract interface defining construction steps |\n| **Concrete Builder** | Implements construction steps, accumulates result |\n| **Director** | (Optional) Orchestrates the builder to construct products in a specific order |\n| **Client** | Uses builder to construct products |\n\n**Key Characteristics:**\n- Fluent interface enabling method chaining\n- Separation of construction from representation\n- Step-by-step object assembly\n- Validation at build stage\n\n---\n\n## 💡 Implementation Example\n\n```java\n// Product: Complex object to build\npublic class Hero {\n private final String name;\n private final Profession profession;\n private final HairType hairType;\n private final HairColor hairColor;\n private final Armor armor;\n private final Weapon weapon;\n\n private Hero(HeroBuilder builder) {\n this.name = builder.name;\n this.profession = builder.profession;\n this.hairType = builder.hairType;\n this.hairColor = builder.hairColor;\n this.armor = builder.armor;\n this.weapon = builder.weapon;\n }\n\n // Builder: Inner class managing construction\n public static class HeroBuilder {\n private final String name;\n private final Profession profession;\n private HairType hairType;\n private HairColor hairColor;\n private Armor armor;\n private Weapon weapon;\n\n // Mandatory parameters in constructor\n public HeroBuilder(Profession profession, String name) {\n this.profession = profession;\n this.name = name;\n }\n\n // Fluent methods for optional parameters\n public HeroBuilder withHairType(HairType hairType) {\n this.hairType = hairType;\n return this;\n }\n\n public HeroBuilder withHairColor(HairColor hairColor) {\n this.hairColor = hairColor;\n return this;\n }\n\n public HeroBuilder withArmor(Armor armor) {\n this.armor = armor;\n return this;\n }\n\n public HeroBuilder withWeapon(Weapon weapon) {\n this.weapon = weapon;\n return this;\n }\n\n // Build: Final step returning the constructed product\n public Hero build() {\n return new Hero(this);\n }\n }\n}\n\n// Usage: Clean, readable, chainable construction\nHero mage = new Hero.HeroBuilder(Profession.MAGE, \"Merlin\")\n .withHairColor(HairColor.BLACK)\n .withWeapon(Weapon.STAFF)\n .build();\n```\n\n**Reasoning:** \n- Separates object construction from its representation\n- Fluent interface improves readability dramatically\n- Mandatory parameters enforced in constructor\n- Optional parameters via fluent methods\n- Immutability achieved through private constructor\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Director {\n -builder: Builder\n +construct()\n }\n class Builder {\n <>\n +buildPartA()\n +buildPartB()\n +getResult()\n }\n class ConcreteBuilder\n class Product\n Client --> Director\n Director --> Builder\n Builder <|-- ConcreteBuilder\n ConcreteBuilder --> Product\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Director: construct()\n Director->>Builder: buildPartA()\n Director->>Builder: buildPartB()\n Builder-->>Director: done\n Client->>Builder: getResult()\n Builder-->>Client: Product\n```\n\n---\n\n## 🔀 Design Principles Emphasized\n\n| Principle | How Applied |\n|-----------|------------|\n| **Single Responsibility** | Builder manages construction; Product manages data |\n| **Separation of Concerns** | Object representation separated from construction logic |\n| **Composition over Inheritance** | Builder uses composition to accumulate object state |\n| **Fluent Interface** | Method chaining improves readability |\n| **Immutability** | Constructor is private; object state set via builder |\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- **Improved Readability:** Fluent interface makes code self-documenting\n- **Flexibility:** Easy to add/remove optional parameters without breaking code\n- **Immutability:** Separating construction enables creation of immutable objects\n- **Complex Initialization:** Handles multi-step construction elegantly\n- **Mandatory Parameter Enforcement:** Constructor ensures required params are present\n- **Validation:** Can validate at build stage before creating object\n\n### Disadvantages ❌\n- **Code Verbosity:** More classes and methods to maintain\n- **Performance Overhead:** Creating builder object adds memory/GC pressure\n- **Complexity for Simple Objects:** Overkill for objects with few parameters\n- **Thread Safety:** Builder itself is not thread-safe; don't share across threads\n- **Builder Proliferation:** Every complex class needs its own builder\n\n---\n\n## 🚫 When NOT to Use\n\n| Scenario | Why Avoid |\n|----------|-----------|\n| **Simple Objects** | Objects with 1-2 parameters; use direct constructors |\n| **Mutable Objects** | Builder is designed for immutability; doesn't benefit mutable objects |\n| **Performance Critical** | Memory overhead of builder may matter in high-frequency scenarios |\n| **All Parameters Optional** | If no mandatory parameters, builder doesn't enforce constraints |\n| **Frequent Modification** | If object needs modification after creation, use setters instead |\n\n---\n\n## ⚠️ Common Anti-Patterns & Misuses\n\n| Anti-Pattern | Problem | Solution |\n|--------------|---------|----------|\n| **Shared Builder Across Threads** | Race conditions when building concurrent products | Create new builder per thread; builders not thread-safe |\n| **Builder Without Validation** | Invalid objects created if validation deferred | Implement validation in `build()` method |\n| **All-Optional Builder** | No constraints on required parameters | Enforce mandatory params in builder constructor |\n| **Complex Directors** | Director hides builder complexity instead of simplifying it | Director should orchestrate, not complicate |\n| **Mutable Product After Build** | Product state modified after construction defeats builder purpose | Keep product immutable; add new builder if changes needed |\n| **Builder with Setters** | Contradicts immutability goal | Use only fluent builder methods, no setters on product |\n\n---\n\n## 🌍 Real-World Use Cases\n\n### Java StringBuilder\n```java\n// StringBuilder is a builder for immutable String\nString text = new StringBuilder()\n .append(\"Hello\")\n .append(\" \")\n .append(\"World\")\n .toString();\n```\n\n### Google Guava - ImmutableList\n```java\n// Guava uses builder for complex immutable collections\nImmutableList list = ImmutableList.builder()\n .add(\"item1\")\n .add(\"item2\")\n .build();\n```\n\n### Lombok @Builder\n```java\n// Lombok annotation auto-generates builder\n@Builder\npublic class User {\n private String name;\n private String email;\n private int age;\n}\n\n// Usage\nUser user = User.builder()\n .name(\"Alice\")\n .email(\"alice@example.com\")\n .age(30)\n .build();\n```\n\n### HTTP Clients (OkHttp)\n```java\n// OkHttp Request builder\nRequest request = new Request.Builder()\n .url(\"https://example.com\")\n .addHeader(\"User-Agent\", \"MyApp\")\n .post(body)\n .build();\n```\n\n### Apache Commons - Configuration\n```java\n// Configuration builder with fluent interface\nConfiguration config = new Configuration.Builder()\n .setDatabaseUrl(\"jdbc:mysql://localhost\")\n .setMaxConnections(50)\n .setReadTimeout(5000)\n .build();\n```\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n| Alternative | When to Prefer |\n|-------------|-----------------|\n| **Telescoping Constructor** | For simple objects with few parameters |\n| **JavaBeans with Setters** | When mutability is acceptable; not ideal for immutability |\n| **Factory Method** | For creating simple objects or choosing implementations |\n| **Abstract Factory** | When building families of related objects |\n| **Fluent Configuration** | Lightweight alternative to builder for configuration objects |\n\n---\n\n## 📝 Best Practices\n\n1. **Enforce Mandatory Parameters:** Place required params in builder constructor\n2. **Use Method Chaining:** Return `this` for fluent interface\n3. **Validate in Build:** Check constraints before creating product\n4. **Keep Builder Simple:** Avoid complex logic; delegate to product\n5. **Consider Lombok:** Use `@Builder` annotation to auto-generate builder code\n6. **Make Product Immutable:** Private constructor, final fields\n7. **Document Optional Parameters:** Clarify defaults and constraints\n8. **Provide Copy Constructor:** Allow building new instance from existing product\n\n---\n\n## 🎓 Related Patterns\n\n- **Factory Pattern:** Can be used within builder to create complex sub-objects\n- **Composite Pattern:** Builder often used to construct composite structures\n- **Strategy Pattern:** Builder can use different strategies for object construction\n- **Template Method:** Builder steps can follow a template structure\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch) - Item 2: Builder Pattern\n- Google Guava Library\n- Lombok @Builder Annotation", + "relatedPatternIds": [ + "singleton", + "abstract-factory", + "factory-method", + "prototype" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🔀 Design Principles Emphasized", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns & Misuses", + "🌍 Real-World Use Cases", + "Java StringBuilder", + "Google Guava - ImmutableList", + "Lombok @Builder", + "HTTP Clients (OkHttp)", + "Apache Commons - Configuration", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References" + ], + "excerpt": "Builder Pattern 📋 Overview The Builder Pattern is a creational pattern that constructs complex objects step by step, separating the construction logic from the representation. It provides a fluent, readable interface for building objects with many optional pa", + "featured": false + }, + { + "id": "chain", + "slug": "chain", + "name": "Chain of Responsibility", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain.", + "intent": "The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain.", + "applicability": [ + "Simple sequential processing", + "One handler always handles the request", + "Performance-critical applications", + "Clear handler hierarchy exists" + ], + "tradeOffs": [], + "alternatives": [ + "Simple sequential processing", + "One handler always handles the request", + "Performance-critical applications", + "Clear handler hierarchy exists" + ], + "keywords": [ + "Chain of Responsibility", + "gof", + "behavioral", + "chain", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "📝 Best Practices", + "📚 References", + "The", + "Responsibility", + "pattern", + "passes", + "request", + "along", + "handlers", + "Each", + "handler", + "decides", + "either", + "process", + "pass", + "next" + ], + "aliases": [ + "chain", + "Chain of Responsibility" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "best practices", + "references" + ], + "githubPath": "gof-patterns/chain", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/chain", + "demoCodePaths": [ + "gof-patterns/chain/src/main/java", + "gof-patterns/chain/src/main", + "gof-patterns/chain/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Chain of Responsibility Pattern

\n

📋 Overview

\n

The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • You need to process a request by multiple handlers without knowing which handler will process it in advance
  • \n
  • You want to decouple the sender of a request from its receiver
  • \n
  • You want to allow adding/removing handlers dynamically
  • \n
\n

Use When:

\n
    \n
  • Multiple objects may handle a request
  • \n
  • You don’t know in advance which object should handle the request
  • \n
  • You want to issue a request to multiple handlers without specifying the receiver explicitly
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
HandlerDefines interface for handling requests and linking handlers
ConcreteHandlerHandles requests or passes them to next handler
ClientInitiates request into the chain
\n
\n

💡 Code Example

\n
public abstract class RequestHandler {\n    protected RequestHandler nextHandler;\n    \n    public void setNextHandler(RequestHandler nextHandler) {\n        this.nextHandler = nextHandler;\n    }\n    \n    public abstract void handleRequest(Request request);\n}\n\npublic class ConcreteHandler extends RequestHandler {\n    @Override\n    public void handleRequest(Request request) {\n        if (canHandle(request)) {\n            process(request);\n        } else if (nextHandler != null) {\n            nextHandler.handleRequest(request);\n        }\n    }\n    \n    private boolean canHandle(Request request) {\n        return request.getType() == RequestType.TYPE_A;\n    }\n    \n    private void process(Request request) {\n        System.out.println("Processing request: " + request);\n    }\n}\n\n// Usage\nRequestHandler handler1 = new ConcreteHandler();\nRequestHandler handler2 = new ConcreteHandler();\nhandler1.setNextHandler(handler2);\nhandler1.handleRequest(new Request(RequestType.TYPE_A));\n
\n

Reasoning: Decouples sender from receiver; handlers decide whether to handle or pass on request dynamically.

\n
\n

🔀 Design Principles

\n
    \n
  • Dependency Inversion Principle
  • \n
  • Single Responsibility Principle
  • \n
  • Open/Closed Principle
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Request\n    class Handler {\n        <<abstract>>\n        -next: Handler\n        +setNext(h: Handler)\n        +handle(r: Request)\n    }\n    class ConcreteHandlerA\n    class ConcreteHandlerB\n    Client --> Handler\n    Handler <|-- ConcreteHandlerA\n    Handler <|-- ConcreteHandlerB\n    Handler --> Handler\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>HandlerA: handle(request)\n    alt canHandle\n        HandlerA-->>Client: handled\n    else pass\n        HandlerA->>HandlerB: handle(request)\n        HandlerB-->>Client: handled\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Decouples sender from receiver
  • \n
  • Dynamic handler assignment
  • \n
  • Easy to add/remove handlers
  • \n
  • Multiple handlers can process request
  • \n
  • Flexible request handling
  • \n
\n

Disadvantages ❌

\n
    \n
  • Request may not be handled
  • \n
  • Debugging difficult with long chains
  • \n
  • Performance impact with many handlers
  • \n
  • Chain configuration complexity
  • \n
  • Potential circular references
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • Simple sequential processing
  • \n
  • One handler always handles the request
  • \n
  • Performance-critical applications
  • \n
  • Clear handler hierarchy exists
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternProblemSolution
Infinite LoopsCircular chain referencesPrevent circular chains
Silent FailuresRequest disappears without handlingAlways handle or log
God HandlerHandler does too muchSplit into multiple handlers
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Event handling in GUI frameworks
  • \n
  • Exception handling in Java
  • \n
  • Servlet filters in web frameworks
  • \n
  • Logging frameworks with appender chains
  • \n
  • Authorization/authentication pipelines
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Define clear handler contract
  2. \n
  3. Document chain behavior
  4. \n
  5. Handle unprocessed requests
  6. \n
  7. Avoid infinite loops in chain
  8. \n
  9. Keep handlers focused
  10. \n
  11. Consider handler ordering
  12. \n
  13. Log at each stage
  14. \n
  15. Provide default handler
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
\n", + "contentMarkdown": "# Chain of Responsibility Pattern\n\n## 📋 Overview\n\nThe **Chain of Responsibility** pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- You need to process a request by multiple handlers without knowing which handler will process it in advance\n- You want to decouple the sender of a request from its receiver\n- You want to allow adding/removing handlers dynamically\n\n**Use When:**\n- Multiple objects may handle a request\n- You don't know in advance which object should handle the request\n- You want to issue a request to multiple handlers without specifying the receiver explicitly\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Handler | Defines interface for handling requests and linking handlers |\n| ConcreteHandler | Handles requests or passes them to next handler |\n| Client | Initiates request into the chain |\n\n---\n\n## 💡 Code Example\n\n```java\npublic abstract class RequestHandler {\n protected RequestHandler nextHandler;\n \n public void setNextHandler(RequestHandler nextHandler) {\n this.nextHandler = nextHandler;\n }\n \n public abstract void handleRequest(Request request);\n}\n\npublic class ConcreteHandler extends RequestHandler {\n @Override\n public void handleRequest(Request request) {\n if (canHandle(request)) {\n process(request);\n } else if (nextHandler != null) {\n nextHandler.handleRequest(request);\n }\n }\n \n private boolean canHandle(Request request) {\n return request.getType() == RequestType.TYPE_A;\n }\n \n private void process(Request request) {\n System.out.println(\"Processing request: \" + request);\n }\n}\n\n// Usage\nRequestHandler handler1 = new ConcreteHandler();\nRequestHandler handler2 = new ConcreteHandler();\nhandler1.setNextHandler(handler2);\nhandler1.handleRequest(new Request(RequestType.TYPE_A));\n```\n\n**Reasoning:** Decouples sender from receiver; handlers decide whether to handle or pass on request dynamically.\n\n---\n\n## 🔀 Design Principles\n\n- **Dependency Inversion Principle**\n- **Single Responsibility Principle**\n- **Open/Closed Principle**\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Request\n class Handler {\n <>\n -next: Handler\n +setNext(h: Handler)\n +handle(r: Request)\n }\n class ConcreteHandlerA\n class ConcreteHandlerB\n Client --> Handler\n Handler <|-- ConcreteHandlerA\n Handler <|-- ConcreteHandlerB\n Handler --> Handler\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>HandlerA: handle(request)\n alt canHandle\n HandlerA-->>Client: handled\n else pass\n HandlerA->>HandlerB: handle(request)\n HandlerB-->>Client: handled\n end\n```\n\n---\n\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Decouples sender from receiver\n- Dynamic handler assignment\n- Easy to add/remove handlers\n- Multiple handlers can process request\n- Flexible request handling\n\n### Disadvantages ❌\n- Request may not be handled\n- Debugging difficult with long chains\n- Performance impact with many handlers\n- Chain configuration complexity\n- Potential circular references\n\n---\n\n## 🚫 When NOT to Use\n\n- Simple sequential processing\n- One handler always handles the request\n- Performance-critical applications\n- Clear handler hierarchy exists\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|--------------|---------|----------|\n| Infinite Loops | Circular chain references | Prevent circular chains |\n| Silent Failures | Request disappears without handling | Always handle or log |\n| God Handler | Handler does too much | Split into multiple handlers |\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Event handling in GUI frameworks\n- Exception handling in Java\n- Servlet filters in web frameworks\n- Logging frameworks with appender chains\n- Authorization/authentication pipelines\n\n---\n\n## 📝 Best Practices\n\n1. Define clear handler contract\n2. Document chain behavior\n3. Handle unprocessed requests\n4. Avoid infinite loops in chain\n5. Keep handlers focused\n6. Consider handler ordering\n7. Log at each stage\n8. Provide default handler\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java", + "relatedPatternIds": [ + "abstract-factory", + "factory-method", + "adapter", + "bridge" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Chain of Responsibility Pattern 📋 Overview The Chain of Responsibility pattern passes a request along a chain of handlers. Each handler decides either to process the request or pass it to the next handler in the chain. 👥 Roles & Responsibilities Role Respons", + "featured": false + }, + { + "id": "command", + "slug": "command", + "name": "Command", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests.", + "intent": "The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Command", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "encapsulates", + "request", + "object", + "allowing", + "parameterization", + "clients", + "with", + "different", + "requests", + "queuing", + "and", + "logging" + ], + "aliases": [ + "command" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/command", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/command", + "demoCodePaths": [ + "gof-patterns/command/src/main/java", + "gof-patterns/command/src/main", + "gof-patterns/command/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Command Pattern

\n

📋 Overview

\n

The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Encapsulate a request as an object
  • \n
  • Decouple the object that invokes an operation from the one that performs it
  • \n
  • Allow undo/redo functionality
  • \n
  • Queue commands for deferred execution
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
CommandDeclares interface for executing operation
ConcreteCommandBinds receiver to action
ReceiverKnows how to perform actual work
InvokerAsks command to carry out request
ClientCreates ConcreteCommand
\n
\n

💡 Code Example

\n
public interface Command {\n    void execute();\n    void undo();\n}\n\npublic class LightOnCommand implements Command {\n    private Light light;\n    \n    public LightOnCommand(Light light) {\n        this.light = light;\n    }\n    \n    @Override\n    public void execute() {\n        light.on();\n    }\n    \n    @Override\n    public void undo() {\n        light.off();\n    }\n}\n\n// Invoker\npublic class RemoteControl {\n    private List<Command> commands = new ArrayList<>();\n    \n    public void pressButton(Command command) {\n        command.execute();\n        commands.add(command);\n    }\n    \n    public void undo() {\n        if (!commands.isEmpty()) {\n            commands.remove(commands.size() - 1).undo();\n        }\n    }\n}\n\n// Usage\nRemoteControl remote = new RemoteControl();\nremote.pressButton(new LightOnCommand(light));\nremote.undo();\n
\n

Reasoning: Requests encapsulated as objects enabling queuing, undoing, and macro commands.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Invoker {\n        -command: Command\n        +setCommand(c: Command)\n        +invoke()\n    }\n    class Command {\n        <<interface>>\n        +execute()\n    }\n    class ConcreteCommand\n    class Receiver {\n        +action()\n    }\n    Client --> Invoker\n    Invoker --> Command\n    Command <|-- ConcreteCommand\n    ConcreteCommand --> Receiver\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Invoker: setCommand(cmd)\n    Client->>Invoker: invoke()\n    Invoker->>Command: execute()\n    Command->>Receiver: action()\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Decouples invoker from receiver
  • \n
  • Easy to add new commands
  • \n
  • Supports undo/redo
  • \n
  • Can queue commands
  • \n
  • Supports command macros
  • \n
  • Deferred execution
  • \n
\n

Disadvantages ❌

\n
    \n
  • More classes required
  • \n
  • Increased memory usage
  • \n
  • Complexity for simple operations
  • \n
  • Undo/redo state management
  • \n
  • Performance overhead
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • GUI button actions
  • \n
  • Undo/redo functionality
  • \n
  • Task queuing systems
  • \n
  • Macro recording
  • \n
  • Transaction systems
  • \n
  • Remote procedure calls
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
\n", + "contentMarkdown": "# Command Pattern\n\n## 📋 Overview\n\nThe **Command** pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Encapsulate a request as an object\n- Decouple the object that invokes an operation from the one that performs it\n- Allow undo/redo functionality\n- Queue commands for deferred execution\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Command | Declares interface for executing operation |\n| ConcreteCommand | Binds receiver to action |\n| Receiver | Knows how to perform actual work |\n| Invoker | Asks command to carry out request |\n| Client | Creates ConcreteCommand |\n\n---\n\n## 💡 Code Example\n\n```java\npublic interface Command {\n void execute();\n void undo();\n}\n\npublic class LightOnCommand implements Command {\n private Light light;\n \n public LightOnCommand(Light light) {\n this.light = light;\n }\n \n @Override\n public void execute() {\n light.on();\n }\n \n @Override\n public void undo() {\n light.off();\n }\n}\n\n// Invoker\npublic class RemoteControl {\n private List commands = new ArrayList<>();\n \n public void pressButton(Command command) {\n command.execute();\n commands.add(command);\n }\n \n public void undo() {\n if (!commands.isEmpty()) {\n commands.remove(commands.size() - 1).undo();\n }\n }\n}\n\n// Usage\nRemoteControl remote = new RemoteControl();\nremote.pressButton(new LightOnCommand(light));\nremote.undo();\n```\n\n**Reasoning:** Requests encapsulated as objects enabling queuing, undoing, and macro commands.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Invoker {\n -command: Command\n +setCommand(c: Command)\n +invoke()\n }\n class Command {\n <>\n +execute()\n }\n class ConcreteCommand\n class Receiver {\n +action()\n }\n Client --> Invoker\n Invoker --> Command\n Command <|-- ConcreteCommand\n ConcreteCommand --> Receiver\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Invoker: setCommand(cmd)\n Client->>Invoker: invoke()\n Invoker->>Command: execute()\n Command->>Receiver: action()\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Decouples invoker from receiver\n- Easy to add new commands\n- Supports undo/redo\n- Can queue commands\n- Supports command macros\n- Deferred execution\n\n### Disadvantages ❌\n- More classes required\n- Increased memory usage\n- Complexity for simple operations\n- Undo/redo state management\n- Performance overhead\n\n---\n\n## 🌍 Real-World Use Cases\n\n- GUI button actions\n- Undo/redo functionality\n- Task queuing systems\n- Macro recording\n- Transaction systems\n- Remote procedure calls\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)", + "relatedPatternIds": [ + "strategy", + "chain", + "observer", + "state" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Command Pattern 📋 Overview The Command pattern encapsulates a request as an object, allowing parameterization of clients with different requests, queuing of requests, and logging of requests. 👥 Roles & Responsibilities Role Responsibility Command Declares in", + "featured": false + }, + { + "id": "composite", + "slug": "composite", + "name": "Composite", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Composite design pattern implementation.", + "intent": "This folder contains the Composite design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Composite", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "composite" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/composite", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/composite", + "demoCodePaths": [ + "gof-patterns/composite/src/main/java", + "gof-patterns/composite/src/main", + "gof-patterns/composite/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Composite Pattern

\n

📋 Overview

\n

This folder contains the Composite design pattern implementation.

\n
\n

🎯 Intent

\n

The composite pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Component {\n        <<interface>>\n        +operation()\n    }\n    class Leaf\n    class Composite {\n        -children: List<Component>\n        +add(c: Component)\n        +operation()\n    }\n    Client --> Component\n    Component <|-- Leaf\n    Component <|-- Composite\n    Composite --> Component\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Composite: operation()\n    loop children\n        Composite->>Component: operation()\n    end\n    Composite-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Composite Pattern\n\n## 📋 Overview\n\nThis folder contains the **Composite** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe composite pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Component {\n <>\n +operation()\n }\n class Leaf\n class Composite {\n -children: List\n +add(c: Component)\n +operation()\n }\n Client --> Component\n Component <|-- Leaf\n Component <|-- Composite\n Composite --> Component\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Composite: operation()\n loop children\n Composite->>Component: operation()\n end\n Composite-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "decorator", + "facade" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Composite Pattern 📋 Overview This folder contains the Composite design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the ", + "featured": false + }, + { + "id": "decorator", + "slug": "decorator", + "name": "Decorator", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Decorator design pattern implementation.", + "intent": "This folder contains the Decorator design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Decorator", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "decorator" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/decorator", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/decorator", + "demoCodePaths": [ + "gof-patterns/decorator/src/main/java", + "gof-patterns/decorator/src/main", + "gof-patterns/decorator/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Decorator Pattern

\n

📋 Overview

\n

This folder contains the Decorator design pattern implementation.

\n
\n

🎯 Intent

\n

The decorator pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Component {\n        <<interface>>\n        +operation()\n    }\n    class ConcreteComponent\n    class Decorator {\n        -component: Component\n        +operation()\n    }\n    class ConcreteDecorator\n    Client --> Component\n    Component <|-- ConcreteComponent\n    Component <|-- Decorator\n    Decorator <|-- ConcreteDecorator\n    Decorator --> Component\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Decorator: operation()\n    Decorator->>Component: operation()\n    Component-->>Decorator: result\n    Decorator-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Decorator Pattern\n\n## 📋 Overview\n\nThis folder contains the **Decorator** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe decorator pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Component {\n <>\n +operation()\n }\n class ConcreteComponent\n class Decorator {\n -component: Component\n +operation()\n }\n class ConcreteDecorator\n Client --> Component\n Component <|-- ConcreteComponent\n Component <|-- Decorator\n Decorator <|-- ConcreteDecorator\n Decorator --> Component\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Decorator: operation()\n Decorator->>Component: operation()\n Component-->>Decorator: result\n Decorator-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "composite", + "facade" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Decorator Pattern 📋 Overview This folder contains the Decorator design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the ", + "featured": false + }, + { + "id": "facade", + "slug": "facade", + "name": "Facade", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Facade design pattern implementation.", + "intent": "This folder contains the Facade design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Facade", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "facade" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/facade", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/facade", + "demoCodePaths": [ + "gof-patterns/facade/src/main/java", + "gof-patterns/facade/src/main", + "gof-patterns/facade/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Facade Pattern

\n

📋 Overview

\n

This folder contains the Facade design pattern implementation.

\n
\n

🎯 Intent

\n

The facade pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Facade {\n        +operation()\n    }\n    class SubsystemA\n    class SubsystemB\n    class SubsystemC\n    Client --> Facade\n    Facade --> SubsystemA\n    Facade --> SubsystemB\n    Facade --> SubsystemC\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Facade: operation()\n    Facade->>SubsystemA: doA()\n    Facade->>SubsystemB: doB()\n    Facade->>SubsystemC: doC()\n    Facade-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Facade Pattern\n\n## 📋 Overview\n\nThis folder contains the **Facade** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe facade pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Facade {\n +operation()\n }\n class SubsystemA\n class SubsystemB\n class SubsystemC\n Client --> Facade\n Facade --> SubsystemA\n Facade --> SubsystemB\n Facade --> SubsystemC\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Facade: operation()\n Facade->>SubsystemA: doA()\n Facade->>SubsystemB: doB()\n Facade->>SubsystemC: doC()\n Facade-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Facade Pattern 📋 Overview This folder contains the Facade design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the src/ d", + "featured": false + }, + { + "id": "factory-method", + "slug": "factory-method", + "name": "Factory Method", + "category": "gof", + "subcategory": "creational", + "summary": "The Factory Method Pattern defines an interface for creating an object, letting subclasses decide which class to instantiate.", + "intent": "The Factory Method Pattern defines an interface for creating an object, letting subclasses decide which class to instantiate.", + "applicability": [ + "**Simple objects with straightforward creation** - Use direct instantiation", + "**Single product type** - Unnecessary abstraction", + "**Static factory methods sufficient** - Use static factories instead" + ], + "tradeOffs": [], + "alternatives": [ + "**Simple objects with straightforward creation** - Use direct instantiation", + "**Single product type** - Unnecessary abstraction", + "**Static factory methods sufficient** - Use static factories instead" + ], + "keywords": [ + "Factory Method", + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "related patterns", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References", + "The", + "Factory", + "Method", + "Pattern", + "defines", + "interface", + "for", + "creating", + "object", + "letting", + "subclasses", + "decide", + "which", + "class", + "instantiate", + "object creation", + "family of objects" + ], + "aliases": [ + "factory method", + "FM" + ], + "tags": [ + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "design principles", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "related patterns", + "references" + ], + "githubPath": "gof-patterns/factory-method", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/factory-method", + "demoCodePaths": [ + "gof-patterns/factory-method/src/main/java", + "gof-patterns/factory-method/src/main", + "gof-patterns/factory-method/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Factory Method Pattern

\n

📋 Overview

\n

The Factory Method Pattern defines an interface for creating an object, letting subclasses decide which class to instantiate.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • You need to create objects but don’t know the concrete class until runtime
  • \n
  • You want subclasses to specify the objects they create
  • \n
  • Object creation logic should be separate from usage
  • \n
\n

Use When:

\n
    \n
  • A class cannot anticipate the type of objects it needs to create
  • \n
  • You want subclasses to specify the objects they create
  • \n
  • Object creation logic should be separate from business logic
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
CreatorDeclares factory method; may provide default implementation
ConcreteCreatorOverrides factory method to create specific product
ProductDeclares interface for objects
ConcreteProductImplements product interface
\n
\n

💡 Code Example

\n
// Product Interface\npublic interface Transport {\n    void deliver(String cargo);\n}\n\n// Concrete Products\npublic class Truck implements Transport {\n    @Override\n    public void deliver(String cargo) {\n        System.out.println("Truck delivering: " + cargo);\n    }\n}\n\n// Creator (Abstract)\npublic abstract class Logistics {\n    abstract Transport createTransport();\n    \n    public void planDelivery(String cargo) {\n        Transport transport = createTransport();\n        transport.deliver(cargo);\n    }\n}\n\n// Concrete Creator\npublic class RoadLogistics extends Logistics {\n    @Override\n    Transport createTransport() {\n        return new Truck();\n    }\n}\n\n// Usage\nLogistics logistics = new RoadLogistics();\nlogistics.planDelivery("Package");\n
\n

Reasoning: Clients depend on abstractions, not concrete classes. Subclasses decide what product to create. Promotes loose coupling and flexibility.

\n
\n

🔀 Design Principles

\n
    \n
  • Dependency Inversion Principle: Depend on abstractions
  • \n
  • Open/Closed Principle: New products without modifying Creator
  • \n
  • Single Responsibility Principle: Creator handles only creation logic
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Creator {\n        <<abstract>>\n        +factoryMethod(): Product\n        +anOperation()\n    }\n    class ConcreteCreator\n    class Product {\n        <<interface>>\n        +use()\n    }\n    class ConcreteProduct\n    Client --> Creator\n    Creator <|-- ConcreteCreator\n    Product <|-- ConcreteProduct\n    Creator --> Product\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Creator: anOperation()\n    Creator->>Creator: factoryMethod()\n    Creator->>Product: use()\n    Product-->>Creator: result\n    Creator-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Decouples creator from concrete products
  • \n
  • Encapsulates creation logic
  • \n
  • Easier to add new product types
  • \n
  • Cleaner code than multiple if-else branches
  • \n
\n

Disadvantages ❌

\n
    \n
  • Creates subclass hierarchy just for creation
  • \n
  • Can be overkill for simple scenarios
  • \n
  • More complex than direct instantiation
  • \n
  • Multiple files for simple variations
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • Simple objects with straightforward creation - Use direct instantiation
  • \n
  • Single product type - Unnecessary abstraction
  • \n
  • Static factory methods sufficient - Use static factories instead
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternProblemSolution
Over-AbstractingCreating factory for every objectUse only when creation logic is complex
Leaky AbstractionsCreator exposes product implementationKeep abstractions strict
Mixing ResponsibilitiesCreator also validates/processesSeparate concerns
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Java Collections: List.of(), Set.of()
  • \n
  • SLF4J: LoggerFactory.getLogger()
  • \n
  • JDBC: DriverManager.getConnection()
  • \n
  • XML: DocumentBuilderFactory.newInstance()
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AlternativeWhen to Use
Abstract FactoryWhen managing families of related products
BuilderWhen object construction is complex
PrototypeWhen cloning is more efficient
\n
\n

📝 Best Practices

\n
    \n
  1. Keep factory interface simple and intuitive
  2. \n
  3. Avoid making factory methods do too much
  4. \n
  5. Document expected exceptions
  6. \n
  7. Provide clear naming for factory methods
  8. \n
  9. Consider static factory methods for simplicity
  10. \n
  11. Ensure thread-safety if needed
  12. \n
  13. Validate inputs before creating objects
  14. \n
  15. Provide sensible defaults where possible
  16. \n
\n
\n

🎓 Related Patterns

\n
    \n
  • Abstract Factory
  • \n
  • Builder Pattern
  • \n
  • Prototype Pattern
  • \n
  • Singleton Pattern
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java (Edith Freeman et al.)
  • \n
\n", + "contentMarkdown": "# Factory Method Pattern\n\n## 📋 Overview\n\nThe **Factory Method Pattern** defines an interface for creating an object, letting subclasses decide which class to instantiate.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- You need to create objects but don't know the concrete class until runtime\n- You want subclasses to specify the objects they create\n- Object creation logic should be separate from usage\n\n**Use When:**\n- A class cannot anticipate the type of objects it needs to create\n- You want subclasses to specify the objects they create\n- Object creation logic should be separate from business logic\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Creator | Declares factory method; may provide default implementation |\n| ConcreteCreator | Overrides factory method to create specific product |\n| Product | Declares interface for objects |\n| ConcreteProduct | Implements product interface |\n\n---\n\n## 💡 Code Example\n\n```java\n// Product Interface\npublic interface Transport {\n void deliver(String cargo);\n}\n\n// Concrete Products\npublic class Truck implements Transport {\n @Override\n public void deliver(String cargo) {\n System.out.println(\"Truck delivering: \" + cargo);\n }\n}\n\n// Creator (Abstract)\npublic abstract class Logistics {\n abstract Transport createTransport();\n \n public void planDelivery(String cargo) {\n Transport transport = createTransport();\n transport.deliver(cargo);\n }\n}\n\n// Concrete Creator\npublic class RoadLogistics extends Logistics {\n @Override\n Transport createTransport() {\n return new Truck();\n }\n}\n\n// Usage\nLogistics logistics = new RoadLogistics();\nlogistics.planDelivery(\"Package\");\n```\n\n**Reasoning:** Clients depend on abstractions, not concrete classes. Subclasses decide what product to create. Promotes loose coupling and flexibility.\n\n---\n\n## 🔀 Design Principles\n\n- **Dependency Inversion Principle:** Depend on abstractions\n- **Open/Closed Principle:** New products without modifying Creator\n- **Single Responsibility Principle:** Creator handles only creation logic\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Creator {\n <>\n +factoryMethod(): Product\n +anOperation()\n }\n class ConcreteCreator\n class Product {\n <>\n +use()\n }\n class ConcreteProduct\n Client --> Creator\n Creator <|-- ConcreteCreator\n Product <|-- ConcreteProduct\n Creator --> Product\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Creator: anOperation()\n Creator->>Creator: factoryMethod()\n Creator->>Product: use()\n Product-->>Creator: result\n Creator-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Decouples creator from concrete products\n- Encapsulates creation logic\n- Easier to add new product types\n- Cleaner code than multiple if-else branches\n\n### Disadvantages ❌\n- Creates subclass hierarchy just for creation\n- Can be overkill for simple scenarios\n- More complex than direct instantiation\n- Multiple files for simple variations\n\n---\n\n## 🚫 When NOT to Use\n\n- **Simple objects with straightforward creation** - Use direct instantiation\n- **Single product type** - Unnecessary abstraction\n- **Static factory methods sufficient** - Use static factories instead\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Problem | Solution |\n|--------------|---------|----------|\n| Over-Abstracting | Creating factory for every object | Use only when creation logic is complex |\n| Leaky Abstractions | Creator exposes product implementation | Keep abstractions strict |\n| Mixing Responsibilities | Creator also validates/processes | Separate concerns |\n\n---\n\n## 🌍 Real-World Use Cases\n\n- **Java Collections:** `List.of()`, `Set.of()`\n- **SLF4J:** `LoggerFactory.getLogger()`\n- **JDBC:** `DriverManager.getConnection()`\n- **XML:** `DocumentBuilderFactory.newInstance()`\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n| Alternative | When to Use |\n|-------------|------------|\n| Abstract Factory | When managing families of related products |\n| Builder | When object construction is complex |\n| Prototype | When cloning is more efficient |\n\n---\n\n## 📝 Best Practices\n\n1. Keep factory interface simple and intuitive\n2. Avoid making factory methods do too much\n3. Document expected exceptions\n4. Provide clear naming for factory methods\n5. Consider static factory methods for simplicity\n6. Ensure thread-safety if needed\n7. Validate inputs before creating objects\n8. Provide sensible defaults where possible\n\n---\n\n## 🎓 Related Patterns\n\n- Abstract Factory\n- Builder Pattern\n- Prototype Pattern\n- Singleton Pattern\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java (Edith Freeman et al.)", + "relatedPatternIds": [ + "abstract-factory", + "builder", + "singleton", + "prototype" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "🔀 Design Principles", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References" + ], + "excerpt": "Factory Method Pattern 📋 Overview The Factory Method Pattern defines an interface for creating an object, letting subclasses decide which class to instantiate. 👥 Roles & Responsibilities Role Responsibility Creator Declares factory method; may provide defaul", + "featured": false + }, + { + "id": "flyweight", + "slug": "flyweight", + "name": "Flyweight", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Flyweight design pattern implementation.", + "intent": "This folder contains the Flyweight design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Flyweight", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "flyweight" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/flyweight", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/flyweight", + "demoCodePaths": [ + "gof-patterns/flyweight/src/main/java", + "gof-patterns/flyweight/src/main", + "gof-patterns/flyweight/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Flyweight Pattern

\n

📋 Overview

\n

This folder contains the Flyweight design pattern implementation.

\n
\n

🎯 Intent

\n

The flyweight pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Flyweight {\n        <<interface>>\n        +operation(extrinsic)\n    }\n    class ConcreteFlyweight\n    class FlyweightFactory {\n        -pool: Map\n        +getFlyweight(key)\n    }\n    Client --> FlyweightFactory\n    Flyweight <|-- ConcreteFlyweight\n    FlyweightFactory --> Flyweight\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>FlyweightFactory: getFlyweight(key)\n    FlyweightFactory-->>Client: Flyweight\n    Client->>Flyweight: operation(extrinsicState)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Flyweight Pattern\n\n## 📋 Overview\n\nThis folder contains the **Flyweight** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe flyweight pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Flyweight {\n <>\n +operation(extrinsic)\n }\n class ConcreteFlyweight\n class FlyweightFactory {\n -pool: Map\n +getFlyweight(key)\n }\n Client --> FlyweightFactory\n Flyweight <|-- ConcreteFlyweight\n FlyweightFactory --> Flyweight\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>FlyweightFactory: getFlyweight(key)\n FlyweightFactory-->>Client: Flyweight\n Client->>Flyweight: operation(extrinsicState)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Flyweight Pattern 📋 Overview This folder contains the Flyweight design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the ", + "featured": false + }, + { + "id": "interpreter", + "slug": "interpreter", + "name": "Interpreter", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Interpreter pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language.", + "intent": "The Interpreter pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Interpreter", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "defines", + "grammatical", + "representation", + "for", + "language", + "and", + "interpret", + "sentences", + "that" + ], + "aliases": [ + "interpreter" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/interpreter", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/interpreter", + "demoCodePaths": [ + "gof-patterns/interpreter/src/main/java", + "gof-patterns/interpreter/src/main", + "gof-patterns/interpreter/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Interpreter Pattern

\n

📋 Overview

\n

The Interpreter pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Define grammar for domain-specific language
  • \n
  • Parse and execute expressions
  • \n
  • Build abstract syntax trees
  • \n
  • Evaluate language sentences
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
AbstractExpressionDefines interpret interface
TerminalExpressionImplements primitive expressions
NonTerminalExpressionImplements composite expressions
ContextGlobal information for interpreter
\n
\n

💡 Implementation

\n
    \n
  • Grammar defined by class hierarchy
  • \n
  • Each expression type is a class
  • \n
  • interpret() evaluates expression
  • \n
  • Recursive interpretation of tree
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Context\n    class AbstractExpression {\n        <<interface>>\n        +interpret(ctx: Context)\n    }\n    class TerminalExpression\n    class NonterminalExpression {\n        -left: AbstractExpression\n        -right: AbstractExpression\n    }\n    Client --> AbstractExpression\n    AbstractExpression <|-- TerminalExpression\n    AbstractExpression <|-- NonterminalExpression\n    AbstractExpression --> Context\n    NonterminalExpression --> AbstractExpression\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>AbstractExpression: interpret(context)\n    AbstractExpression->>AbstractExpression: interpret(child)\n    AbstractExpression-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Easy to modify grammar
  • \n
  • Grammar in code form
  • \n
  • Extensible expressions
  • \n
  • Recursive evaluation
  • \n
  • Natural language representation
  • \n
\n

Disadvantages ❌

\n
    \n
  • Complex for large grammars
  • \n
  • Performance overhead
  • \n
  • Many classes required
  • \n
  • Difficult to parse
  • \n
  • Memory consumption
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Expression evaluators
  • \n
  • DSL (Domain-Specific Language) implementation
  • \n
  • SQL query processing
  • \n
  • Regular expression engines
  • \n
  • Configuration file parsing
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Language design patterns
  • \n
\n", + "contentMarkdown": "# Interpreter Pattern\n\n## 📋 Overview\n\nThe **Interpreter** pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Define grammar for domain-specific language\n- Parse and execute expressions\n- Build abstract syntax trees\n- Evaluate language sentences\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| AbstractExpression | Defines interpret interface |\n| TerminalExpression | Implements primitive expressions |\n| NonTerminalExpression | Implements composite expressions |\n| Context | Global information for interpreter |\n\n---\n\n## 💡 Implementation\n\n- Grammar defined by class hierarchy\n- Each expression type is a class\n- interpret() evaluates expression\n- Recursive interpretation of tree\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Context\n class AbstractExpression {\n <>\n +interpret(ctx: Context)\n }\n class TerminalExpression\n class NonterminalExpression {\n -left: AbstractExpression\n -right: AbstractExpression\n }\n Client --> AbstractExpression\n AbstractExpression <|-- TerminalExpression\n AbstractExpression <|-- NonterminalExpression\n AbstractExpression --> Context\n NonterminalExpression --> AbstractExpression\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>AbstractExpression: interpret(context)\n AbstractExpression->>AbstractExpression: interpret(child)\n AbstractExpression-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Easy to modify grammar\n- Grammar in code form\n- Extensible expressions\n- Recursive evaluation\n- Natural language representation\n\n### Disadvantages ❌\n- Complex for large grammars\n- Performance overhead\n- Many classes required\n- Difficult to parse\n- Memory consumption\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Expression evaluators\n- DSL (Domain-Specific Language) implementation\n- SQL query processing\n- Regular expression engines\n- Configuration file parsing\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Language design patterns", + "relatedPatternIds": [ + "mediator", + "iterator", + "memento", + "visitor" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Interpreter Pattern 📋 Overview The Interpreter pattern defines a grammatical representation for a language and an interpreter to interpret sentences in that language. 👥 Roles & Responsibilities Role Responsibility AbstractExpression Defines interpret interfa", + "featured": false + }, + { + "id": "iterator", + "slug": "iterator", + "name": "Iterator", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.", + "intent": "The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Iterator", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "provides", + "way", + "access", + "elements", + "collection", + "sequentially", + "without", + "exposing", + "its", + "underlying", + "representation" + ], + "aliases": [ + "iterator" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/iterator", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/iterator", + "demoCodePaths": [ + "gof-patterns/iterator/src/main/java", + "gof-patterns/iterator/src/main", + "gof-patterns/iterator/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Iterator Pattern

\n

📋 Overview

\n

The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Access collection elements without exposing structure
  • \n
  • Support multiple simultaneous traversals
  • \n
  • Provide uniform interface for different collections
  • \n
  • Hide collection implementation details
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
IteratorDefines interface for traversal
ConcreteIteratorImplements traversal logic
CollectionDefines interface for creating iterator
ConcreteCollectionReturns ConcreteIterator
\n
\n

💡 Implementation

\n

Java’s Iterator interface:

\n
    \n
  • hasNext(): Check if more elements
  • \n
  • next(): Get next element
  • \n
  • remove(): Remove current element
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Iterator {\n        <<interface>>\n        +hasNext()\n        +next()\n    }\n    class ConcreteIterator\n    class Aggregate {\n        <<interface>>\n        +createIterator(): Iterator\n    }\n    class ConcreteAggregate\n    Client --> Aggregate\n    Aggregate <|-- ConcreteAggregate\n    Iterator <|-- ConcreteIterator\n    ConcreteAggregate --> ConcreteIterator\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Aggregate: createIterator()\n    Aggregate-->>Client: Iterator\n    loop until done\n        Client->>Iterator: hasNext()\n        Client->>Iterator: next()\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Uniform traversal interface
  • \n
  • Hides collection structure
  • \n
  • Supports multiple iterations
  • \n
  • Decouples collection from traversal
  • \n
  • Different iteration strategies
  • \n
\n

Disadvantages ❌

\n
    \n
  • Additional complexity
  • \n
  • Iterator overhead
  • \n
  • State management in iterator
  • \n
  • Concurrent modification issues
  • \n
  • Performance impact
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Java Collections Framework
  • \n
  • Database result set traversal
  • \n
  • File system traversal
  • \n
  • Tree/graph traversal
  • \n
  • Stream processing
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Java Collections Framework
  • \n
  • Iterator design
  • \n
\n", + "contentMarkdown": "# Iterator Pattern\n\n## 📋 Overview\n\nThe **Iterator** pattern provides a way to access elements of a collection sequentially without exposing its underlying representation.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Access collection elements without exposing structure\n- Support multiple simultaneous traversals\n- Provide uniform interface for different collections\n- Hide collection implementation details\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Iterator | Defines interface for traversal |\n| ConcreteIterator | Implements traversal logic |\n| Collection | Defines interface for creating iterator |\n| ConcreteCollection | Returns ConcreteIterator |\n\n---\n\n## 💡 Implementation\n\nJava's Iterator interface:\n- hasNext(): Check if more elements\n- next(): Get next element\n- remove(): Remove current element\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Iterator {\n <>\n +hasNext()\n +next()\n }\n class ConcreteIterator\n class Aggregate {\n <>\n +createIterator(): Iterator\n }\n class ConcreteAggregate\n Client --> Aggregate\n Aggregate <|-- ConcreteAggregate\n Iterator <|-- ConcreteIterator\n ConcreteAggregate --> ConcreteIterator\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Aggregate: createIterator()\n Aggregate-->>Client: Iterator\n loop until done\n Client->>Iterator: hasNext()\n Client->>Iterator: next()\n end\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Uniform traversal interface\n- Hides collection structure\n- Supports multiple iterations\n- Decouples collection from traversal\n- Different iteration strategies\n\n### Disadvantages ❌\n- Additional complexity\n- Iterator overhead\n- State management in iterator\n- Concurrent modification issues\n- Performance impact\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Java Collections Framework\n- Database result set traversal\n- File system traversal\n- Tree/graph traversal\n- Stream processing\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Java Collections Framework\n- Iterator design", + "relatedPatternIds": [ + "visitor", + "interpreter", + "memento", + "mediator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Iterator Pattern 📋 Overview The Iterator pattern provides a way to access elements of a collection sequentially without exposing its underlying representation. 👥 Roles & Responsibilities Role Responsibility Iterator Defines interface for traversal ConcreteIt", + "featured": false + }, + { + "id": "mediator", + "slug": "mediator", + "name": "Mediator", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Mediator pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.", + "intent": "The Mediator pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Mediator", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "defines", + "object", + "that", + "encapsulates", + "how", + "set", + "objects", + "interact", + "promotes", + "loose", + "coupling", + "keeping", + "from", + "referring", + "each", + "other", + "explicitly", + "and", + "lets", + "you", + "vary", + "their", + "interaction", + "independently" + ], + "aliases": [ + "mediator" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/mediator", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/mediator", + "demoCodePaths": [ + "gof-patterns/mediator/src/main/java", + "gof-patterns/mediator/src/main", + "gof-patterns/mediator/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Mediator Pattern

\n

📋 Overview

\n

The Mediator pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Objects communicate in complex ways
  • \n
  • Direct references create tight coupling
  • \n
  • Communication logic scattered across classes
  • \n
  • Adding new interaction types requires modifications
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
MediatorDefines interface for communication
ConcreteMediatorImplements interaction logic
ColleagueCommunicates only with mediator
\n
    \n
  • ConcreteColleague | Implements colleague behavior |
  • \n
\n
\n

💡 Implementation

\n
    \n
  • Colleagues reference mediator
  • \n
  • Mediator knows all colleagues
  • \n
  • Communication routed through mediator
  • \n
  • Mediator implements distribution logic
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Mediator {\n        <<interface>>\n        +notify(sender, event)\n    }\n    class ConcreteMediator\n    class Colleague {\n        -mediator: Mediator\n        +send(event)\n    }\n    class ColleagueA\n    class ColleagueB\n    Mediator <|-- ConcreteMediator\n    Colleague <|-- ColleagueA\n    Colleague <|-- ColleagueB\n    Colleague --> Mediator\n    ConcreteMediator --> ColleagueA\n    ConcreteMediator --> ColleagueB\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    participant ColleagueA\n    participant Mediator\n    participant ColleagueB\n    ColleagueA->>Mediator: notify(A, event)\n    Mediator->>ColleagueB: receive(event)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Decouples colleagues
  • \n
  • Centralizes control
  • \n
  • Easy to modify interactions
  • \n
  • Simplifies colleague classes
  • \n
  • Reusable colleagues
  • \n
\n

Disadvantages ❌

\n
    \n
  • Mediator complexity
  • \n
  • God Object risk
  • \n
  • Performance overhead
  • \n
  • Debugging difficulty
  • \n
  • Hidden dependencies
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • ChatRoom mediator
  • \n
  • Dialog box coordinators
  • \n
  • Air traffic control
  • \n
  • Central event dispatcher
  • \n
  • Workflow engines
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Coordination patterns
  • \n
\n", + "contentMarkdown": "# Mediator Pattern\n\n## 📋 Overview\n\nThe **Mediator** pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Objects communicate in complex ways\n- Direct references create tight coupling\n- Communication logic scattered across classes\n- Adding new interaction types requires modifications\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Mediator | Defines interface for communication |\n| ConcreteMediator | Implements interaction logic |\n| Colleague | Communicates only with mediator |\n- ConcreteColleague | Implements colleague behavior |\n\n---\n\n## 💡 Implementation\n\n- Colleagues reference mediator\n- Mediator knows all colleagues\n- Communication routed through mediator\n- Mediator implements distribution logic\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Mediator {\n <>\n +notify(sender, event)\n }\n class ConcreteMediator\n class Colleague {\n -mediator: Mediator\n +send(event)\n }\n class ColleagueA\n class ColleagueB\n Mediator <|-- ConcreteMediator\n Colleague <|-- ColleagueA\n Colleague <|-- ColleagueB\n Colleague --> Mediator\n ConcreteMediator --> ColleagueA\n ConcreteMediator --> ColleagueB\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n participant ColleagueA\n participant Mediator\n participant ColleagueB\n ColleagueA->>Mediator: notify(A, event)\n Mediator->>ColleagueB: receive(event)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Decouples colleagues\n- Centralizes control\n- Easy to modify interactions\n- Simplifies colleague classes\n- Reusable colleagues\n\n### Disadvantages ❌\n- Mediator complexity\n- God Object risk\n- Performance overhead\n- Debugging difficulty\n- Hidden dependencies\n\n---\n\n## 🌍 Real-World Use Cases\n\n- ChatRoom mediator\n- Dialog box coordinators\n- Air traffic control\n- Central event dispatcher\n- Workflow engines\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Coordination patterns", + "relatedPatternIds": [ + "interpreter", + "visitor", + "memento", + "observer" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Mediator Pattern 📋 Overview The Mediator pattern defines an object that encapsulates how a set of objects interact. It promotes loose coupling by keeping objects from referring to each other explicitly, and lets you vary their interaction independently. 👥 Ro", + "featured": false + }, + { + "id": "memento", + "slug": "memento", + "name": "Memento", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Memento pattern captures and externalizes an object's internal state without violating encapsulation, and allows the object to be restored to this state later.", + "intent": "The Memento pattern captures and externalizes an object's internal state without violating encapsulation, and allows the object to be restored to this state later.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Memento", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "captures", + "and", + "externalizes", + "object", + "internal", + "state", + "without", + "violating", + "encapsulation", + "allows", + "restored", + "this", + "later" + ], + "aliases": [ + "memento" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/memento", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/memento", + "demoCodePaths": [ + "gof-patterns/memento/src/main/java", + "gof-patterns/memento/src/main", + "gof-patterns/memento/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Memento Pattern

\n

📋 Overview

\n

The Memento pattern captures and externalizes an object’s internal state without violating encapsulation, and allows the object to be restored to this state later.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Save and restore object state
  • \n
  • Implement undo/redo functionality
  • \n
  • Without exposing internal structure
  • \n
  • Without violating encapsulation
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
OriginatorCreates memento, uses memento to restore state
MementoStores state snapshot
CaretakerManages mementos
\n
\n

💡 Implementation

\n
    \n
  • Memento stores state snapshot
  • \n
  • Originator creates/uses mementos
  • \n
  • Caretaker manages memento collection
  • \n
  • Enables state history management
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Originator {\n        +createMemento(): Memento\n        +restore(m: Memento)\n    }\n    class Memento\n    class Caretaker {\n        -history: List<Memento>\n    }\n    Client --> Originator\n    Client --> Caretaker\n    Originator --> Memento\n    Caretaker --> Memento\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Originator: createMemento()\n    Originator-->>Client: Memento\n    Client->>Caretaker: store(memento)\n    Client->>Originator: restore(memento)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Encapsulation preserved
  • \n
  • Simple undo/redo
  • \n
  • State history management
  • \n
  • Serialization support
  • \n
  • Snapshot capability
  • \n
\n

Disadvantages ❌

\n
    \n
  • Memory overhead
  • \n
  • Performance cost for large objects
  • \n
  • Serialization complexity
  • \n
  • State consistency management
  • \n
  • Storage requirements
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Text editor undo/redo
  • \n
  • Database transactions
  • \n
  • Game state saves
  • \n
  • Configuration snapshots
  • \n
  • Version control systems
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • State management patterns
  • \n
\n", + "contentMarkdown": "# Memento Pattern\n\n## 📋 Overview\n\nThe **Memento** pattern captures and externalizes an object's internal state without violating encapsulation, and allows the object to be restored to this state later.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Save and restore object state\n- Implement undo/redo functionality\n- Without exposing internal structure\n- Without violating encapsulation\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Originator | Creates memento, uses memento to restore state |\n| Memento | Stores state snapshot |\n| Caretaker | Manages mementos |\n\n---\n\n## 💡 Implementation\n\n- Memento stores state snapshot\n- Originator creates/uses mementos\n- Caretaker manages memento collection\n- Enables state history management\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Originator {\n +createMemento(): Memento\n +restore(m: Memento)\n }\n class Memento\n class Caretaker {\n -history: List\n }\n Client --> Originator\n Client --> Caretaker\n Originator --> Memento\n Caretaker --> Memento\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Originator: createMemento()\n Originator-->>Client: Memento\n Client->>Caretaker: store(memento)\n Client->>Originator: restore(memento)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Encapsulation preserved\n- Simple undo/redo\n- State history management\n- Serialization support\n- Snapshot capability\n\n### Disadvantages ❌\n- Memory overhead\n- Performance cost for large objects\n- Serialization complexity\n- State consistency management\n- Storage requirements\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Text editor undo/redo\n- Database transactions\n- Game state saves\n- Configuration snapshots\n- Version control systems\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- State management patterns", + "relatedPatternIds": [ + "mediator", + "visitor", + "interpreter", + "iterator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Memento Pattern 📋 Overview The Memento pattern captures and externalizes an object's internal state without violating encapsulation, and allows the object to be restored to this state later. 👥 Roles & Responsibilities Role Responsibility Originator Creates m", + "featured": false + }, + { + "id": "observer", + "slug": "observer", + "name": "Observer", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Observer pattern defines a one to many dependency between objects so that when one object changes state, all its dependents are notified automatically.", + "intent": "The Observer pattern defines a one to many dependency between objects so that when one object changes state, all its dependents are notified automatically.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Observer", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "defines", + "one", + "many", + "dependency", + "between", + "objects", + "that", + "when", + "object", + "changes", + "state", + "all", + "its", + "dependents", + "are", + "notified", + "automatically", + "event-driven", + "pub-sub" + ], + "aliases": [ + "observer" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/observer", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/observer", + "demoCodePaths": [ + "gof-patterns/observer/src/main/java", + "gof-patterns/observer/src/main", + "gof-patterns/observer/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Observer Pattern

\n

📋 Overview

\n

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • An object’s state changes and other objects need to be notified
  • \n
  • Notify multiple objects without tight coupling
  • \n
  • Enable event-driven architecture
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
SubjectKnows observers, provides interface to attach/detach
ObserverDefines interface for update notification
ConcreteObserverStores reference to Subject, implements update
ConcreteSubjectStores state, sends notifications on change
\n
\n

💡 Code Example

\n
public interface Observer {\n    void update(String message);\n}\n\npublic class Subject {\n    private List<Observer> observers = new ArrayList<>();\n    \n    public void attach(Observer observer) {\n        observers.add(observer);\n    }\n    \n    public void detach(Observer observer) {\n        observers.remove(observer);\n    }\n    \n    public void notifyObservers(String message) {\n        for (Observer observer : observers) {\n            observer.update(message);\n        }\n    }\n}\n\npublic class ConcreteObserver implements Observer {\n    private String name;\n    \n    @Override\n    public void update(String message) {\n        System.out.println(name + " received: " + message);\n    }\n}\n\n// Usage\nSubject subject = new Subject();\nObserver obs1 = new ConcreteObserver();\nsubject.attach(obs1);\nsubject.notifyObservers("Event occurred");\n
\n

Reasoning: Loose coupling between Subject and Observers; enables dynamic subscription model.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Subject {\n        +attach(o: Observer)\n        +detach(o: Observer)\n        +notify()\n    }\n    class ConcreteSubject\n    class Observer {\n        <<interface>>\n        +update()\n    }\n    class ConcreteObserver\n    Subject <|-- ConcreteSubject\n    Observer <|-- ConcreteObserver\n    Subject --> Observer\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    participant Observer\n    participant Subject\n    Observer->>Subject: attach()\n    Subject->>Subject: changeState()\n    Subject->>Observer: notify()\n    Observer->>Observer: update()\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Loose coupling
  • \n
  • Dynamic observer management
  • \n
  • Supports broadcast communications
  • \n
  • Natural event handling
  • \n
  • Promotes reactive programming
  • \n
\n

Disadvantages ❌

\n
    \n
  • Observer ordering unpredictable
  • \n
  • Memory overhead (observer references)
  • \n
  • Performance impact with many observers
  • \n
  • Difficult to trace event flow
  • \n
  • Can lead to memory leaks
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Event listeners in GUI frameworks
  • \n
  • Message passing systems
  • \n
  • Reactive programming libraries
  • \n
  • Model-View patterns
  • \n
  • Pub/Sub systems
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Reactive Programming concepts
  • \n
  • Event-driven architecture
  • \n
\n", + "contentMarkdown": "# Observer Pattern\n\n## 📋 Overview\n\nThe **Observer** pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified automatically.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- An object's state changes and other objects need to be notified\n- Notify multiple objects without tight coupling\n- Enable event-driven architecture\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Subject | Knows observers, provides interface to attach/detach |\n| Observer | Defines interface for update notification |\n| ConcreteObserver | Stores reference to Subject, implements update |\n| ConcreteSubject | Stores state, sends notifications on change |\n\n---\n\n## 💡 Code Example\n\n```java\npublic interface Observer {\n void update(String message);\n}\n\npublic class Subject {\n private List observers = new ArrayList<>();\n \n public void attach(Observer observer) {\n observers.add(observer);\n }\n \n public void detach(Observer observer) {\n observers.remove(observer);\n }\n \n public void notifyObservers(String message) {\n for (Observer observer : observers) {\n observer.update(message);\n }\n }\n}\n\npublic class ConcreteObserver implements Observer {\n private String name;\n \n @Override\n public void update(String message) {\n System.out.println(name + \" received: \" + message);\n }\n}\n\n// Usage\nSubject subject = new Subject();\nObserver obs1 = new ConcreteObserver();\nsubject.attach(obs1);\nsubject.notifyObservers(\"Event occurred\");\n```\n\n**Reasoning:** Loose coupling between Subject and Observers; enables dynamic subscription model.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Subject {\n +attach(o: Observer)\n +detach(o: Observer)\n +notify()\n }\n class ConcreteSubject\n class Observer {\n <>\n +update()\n }\n class ConcreteObserver\n Subject <|-- ConcreteSubject\n Observer <|-- ConcreteObserver\n Subject --> Observer\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n participant Observer\n participant Subject\n Observer->>Subject: attach()\n Subject->>Subject: changeState()\n Subject->>Observer: notify()\n Observer->>Observer: update()\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Loose coupling\n- Dynamic observer management\n- Supports broadcast communications\n- Natural event handling\n- Promotes reactive programming\n\n### Disadvantages ❌\n- Observer ordering unpredictable\n- Memory overhead (observer references)\n- Performance impact with many observers\n- Difficult to trace event flow\n- Can lead to memory leaks\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Event listeners in GUI frameworks\n- Message passing systems\n- Reactive programming libraries\n- Model-View patterns\n- Pub/Sub systems\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Reactive Programming concepts\n- Event-driven architecture", + "relatedPatternIds": [ + "state", + "strategy", + "mediator", + "command" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Observer Pattern 📋 Overview The Observer pattern defines a one to many dependency between objects so that when one object changes state, all its dependents are notified automatically. 👥 Roles & Responsibilities Role Responsibility Subject Knows observers, pr", + "featured": true + }, + { + "id": "prototype", + "slug": "prototype", + "name": "Prototype", + "category": "gof", + "subcategory": "creational", + "summary": "This folder contains the Prototype design pattern implementation.", + "intent": "This folder contains the Prototype design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Prototype", + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "prototype" + ], + "tags": [ + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/prototype", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/prototype", + "demoCodePaths": [ + "gof-patterns/prototype/src/main/java", + "gof-patterns/prototype/src/main", + "gof-patterns/prototype/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Prototype Pattern

\n

📋 Overview

\n

This folder contains the Prototype design pattern implementation.

\n
\n

🎯 Intent

\n

The prototype pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Prototype {\n        <<interface>>\n        +clone()\n    }\n    class ConcretePrototype\n    Client --> Prototype\n    Prototype <|-- ConcretePrototype\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Prototype: clone()\n    Prototype-->>Client: copy\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Prototype Pattern\n\n## 📋 Overview\n\nThis folder contains the **Prototype** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe prototype pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Prototype {\n <>\n +clone()\n }\n class ConcretePrototype\n Client --> Prototype\n Prototype <|-- ConcretePrototype\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Prototype: clone()\n Prototype-->>Client: copy\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Prototype Pattern 📋 Overview This folder contains the Prototype design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the ", + "featured": false + }, + { + "id": "proxy", + "slug": "proxy", + "name": "Proxy", + "category": "gof", + "subcategory": "structural", + "summary": "This folder contains the Proxy design pattern implementation.", + "intent": "This folder contains the Proxy design pattern implementation.", + "applicability": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "tradeOffs": [], + "alternatives": [ + "For simple scenarios where direct solutions suffice", + "When performance is critical and overhead is unacceptable", + "In situations where the pattern doesn't naturally fit" + ], + "keywords": [ + "Proxy", + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References", + "This", + "folder", + "contains", + "the", + "design", + "pattern", + "implementation" + ], + "aliases": [ + "proxy" + ], + "tags": [ + "gof", + "structural", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns", + "real-world use cases", + "alternatives similar patterns", + "best practices", + "references" + ], + "githubPath": "gof-patterns/proxy", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/proxy", + "demoCodePaths": [ + "gof-patterns/proxy/src/main/java", + "gof-patterns/proxy/src/main", + "gof-patterns/proxy/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

Proxy Pattern

\n

📋 Overview

\n

This folder contains the Proxy design pattern implementation.

\n
\n

🎯 Intent

\n

The proxy pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.

\n
\n

👥 Roles & Responsibilities

\n

This pattern involves multiple roles working together to achieve separation of concerns and flexibility.

\n
\n

💡 Code Example

\n

Please see the src/ directory for complete, executable code examples demonstrating this pattern.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Subject {\n        <<interface>>\n        +request()\n    }\n    class RealSubject\n    class Proxy {\n        -real: RealSubject\n        +request()\n    }\n    Client --> Subject\n    Subject <|-- RealSubject\n    Subject <|-- Proxy\n    Proxy --> RealSubject\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Proxy: request()\n    Proxy->>RealSubject: request()\n    RealSubject-->>Proxy: result\n    Proxy-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Provides structured solution
  • \n
  • Promotes code reusability
  • \n
  • Improves maintainability
  • \n
\n

Disadvantages ❌

\n
    \n
  • May add complexity
  • \n
  • Performance overhead
  • \n
  • Learning curve
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For simple scenarios where direct solutions suffice
  • \n
  • When performance is critical and overhead is unacceptable
  • \n
  • In situations where the pattern doesn’t naturally fit
  • \n
\n
\n

⚠️ Common Anti-Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternIssueSolution
OveruseUsing pattern unnecessarilyApply YAGNI principle
MisapplicationWrong context for patternStudy pattern requirements
ComplexityPattern makes code harderSimplify or choose different pattern
\n
\n

🌍 Real-World Use Cases

\n

This pattern appears frequently in:

\n
    \n
  • Enterprise applications
  • \n
  • Framework and library design
  • \n
  • System integration scenarios
  • \n
\n
\n

🔗 Alternatives & Similar Patterns

\n
    \n
  • Other structural/behavioral patterns
  • \n
  • Simpler direct approaches
  • \n
  • Complementary patterns
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Understand the problem before applying the pattern
  2. \n
  3. Document your pattern usage clearly
  4. \n
  5. Keep implementations simple
  6. \n
  7. Test thoroughly
  8. \n
  9. Consider performance implications
  10. \n
  11. Review periodically for improvements
  12. \n
  13. Teach team members about the pattern
  14. \n
  15. Refactor if pattern no longer applies
  16. \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Design Patterns in Java
  • \n
  • Refactoring Guru
  • \n
\n

For detailed implementation, see the source files in src/.

\n", + "contentMarkdown": "# Proxy Pattern\n\n## 📋 Overview\n\nThis folder contains the **Proxy** design pattern implementation.\n\n---\n\n## 🎯 Intent\n\nThe proxy pattern solves a specific structural or behavioral problem in software design by providing reusable solutions.\n\n---\n\n## 👥 Roles & Responsibilities\n\nThis pattern involves multiple roles working together to achieve separation of concerns and flexibility.\n\n---\n\n## 💡 Code Example\n\nPlease see the `src/` directory for complete, executable code examples demonstrating this pattern.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Subject {\n <>\n +request()\n }\n class RealSubject\n class Proxy {\n -real: RealSubject\n +request()\n }\n Client --> Subject\n Subject <|-- RealSubject\n Subject <|-- Proxy\n Proxy --> RealSubject\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Proxy: request()\n Proxy->>RealSubject: request()\n RealSubject-->>Proxy: result\n Proxy-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Provides structured solution\n- Promotes code reusability\n- Improves maintainability\n\n### Disadvantages ❌\n- May add complexity\n- Performance overhead\n- Learning curve\n\n---\n\n## 🚫 When NOT to Use\n\n- For simple scenarios where direct solutions suffice\n- When performance is critical and overhead is unacceptable\n- In situations where the pattern doesn't naturally fit\n\n---\n\n## ⚠️ Common Anti-Patterns\n\n| Anti-Pattern | Issue | Solution |\n|--------------|-------|----------|\n| Overuse | Using pattern unnecessarily | Apply YAGNI principle |\n| Misapplication | Wrong context for pattern | Study pattern requirements |\n| Complexity | Pattern makes code harder | Simplify or choose different pattern |\n\n---\n\n## 🌍 Real-World Use Cases\n\nThis pattern appears frequently in:\n- Enterprise applications\n- Framework and library design\n- System integration scenarios\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n- Other structural/behavioral patterns\n- Simpler direct approaches\n- Complementary patterns\n\n---\n\n## 📝 Best Practices\n\n1. Understand the problem before applying the pattern\n2. Document your pattern usage clearly\n3. Keep implementations simple\n4. Test thoroughly\n5. Consider performance implications\n6. Review periodically for improvements\n7. Teach team members about the pattern\n8. Refactor if pattern no longer applies\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Design Patterns in Java\n- Refactoring Guru\n\nFor detailed implementation, see the source files in `src/`.", + "relatedPatternIds": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "📚 References" + ], + "excerpt": "Proxy Pattern 📋 Overview This folder contains the Proxy design pattern implementation. 👥 Roles & Responsibilities This pattern involves multiple roles working together to achieve separation of concerns and flexibility. 💡 Code Example Please see the src/ dir", + "featured": false + }, + { + "id": "singleton", + "slug": "singleton", + "name": "Singleton", + "category": "gof", + "subcategory": "creational", + "summary": "The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to access that instance universally.", + "intent": "The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to access that instance universally.", + "applicability": [ + "Scenario Why Avoid Stateful Objects Sharing state across all clients leads to unexpected side effects Testable Systems Global dependencies make unit testing extremely difficult Multiple Instances Needed If business logic later requires multiple instances, refactoring is painful Distributed Systems Each JVM/process gets its own instance", + "doesn't guarantee global uniqueness Simple Services Dependency Injection (DI) containers provide same benefits with better flexibility" + ], + "tradeOffs": [], + "alternatives": [ + "Scenario Why Avoid Stateful Objects Sharing state across all clients leads to unexpected side effects Testable Systems Global dependencies make unit testing extremely difficult Multiple Instances Needed If business logic later requires multiple instances, refactoring is painful Distributed Systems Each JVM/process gets its own instance", + "doesn't guarantee global uniqueness Simple Services Dependency Injection (DI) containers provide same benefits with better flexibility" + ], + "keywords": [ + "Singleton", + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "implementation strategies", + "1 eager initialization", + "2 lazy initialization with synchronization", + "3 double-checked locking", + "4 bill pugh singleton class loader", + "class diagram", + "sequence diagram", + "design principles emphasized", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns misuses", + "real-world use cases", + "spring framework", + "log4j / slf4j", + "database connection pool", + "configuration manager", + "alternatives similar patterns", + "best practices", + "related patterns", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation Strategies", + "1. **Eager Initialization**", + "2. **Lazy Initialization with Synchronization**", + "3. **Double-Checked Locking**", + "4. **Bill Pugh Singleton (Class Loader)**", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🔀 Design Principles Emphasized", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns & Misuses", + "🌍 Real-World Use Cases", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References", + "The", + "Pattern", + "ensures", + "that", + "class", + "has", + "only", + "one", + "instance", + "and", + "provides", + "global", + "point", + "access", + "This", + "restricts", + "object", + "instantiation", + "single", + "while", + "providing", + "mechanism", + "universally" + ], + "aliases": [ + "singleton" + ], + "tags": [ + "gof", + "creational", + "overview", + "intent", + "roles responsibilities", + "implementation strategies", + "1 eager initialization", + "2 lazy initialization with synchronization", + "3 double-checked locking", + "4 bill pugh singleton class loader", + "class diagram", + "sequence diagram", + "design principles emphasized", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "common anti-patterns misuses", + "real-world use cases", + "spring framework", + "log4j / slf4j", + "database connection pool", + "configuration manager", + "alternatives similar patterns", + "best practices", + "related patterns", + "references" + ], + "githubPath": "gof-patterns/singleton", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/singleton", + "demoCodePaths": [ + "gof-patterns/singleton/src/main/java", + "gof-patterns/singleton/src/main", + "gof-patterns/singleton/src" + ], + "hasTests": true, + "readingTimeMinutes": 5, + "contentHtml": "

Singleton Pattern

\n

📋 Overview

\n

The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to access that instance universally.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • You need to guarantee that only one instance of a class exists throughout the application lifecycle
  • \n
  • Multiple instances would cause logical errors or resource conflicts (e.g., database connections, configuration managers, logging services)
  • \n
  • You need a globally accessible point of access to this single instance without passing references through all layers
  • \n
\n

Use When:

\n
    \n
  • You need a single, shared resource manager (connection pools, thread pools, caches)
  • \n
  • You need a centralized configuration holder or registry
  • \n
  • You need exactly one instance of a service to coordinate system-wide activities
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
SingletonEnsures only one instance exists via private constructor; provides static method to access the single instance
ClientAccesses the singleton instance through the public static accessor method
\n

Key Characteristics:

\n
    \n
  • Private constructor prevents external instantiation
  • \n
  • Static instance variable holds the single object
  • \n
  • Public static accessor method (getInstance()) returns the instance
  • \n
  • Thread-safety considerations for multi-threaded environments
  • \n
\n
\n

💡 Implementation Strategies

\n

This pattern has multiple implementations, each with different trade-offs:

\n

1. Eager Initialization

\n
public class EagerInitializedSingleton {\n    private static final EagerInitializedSingleton instance = \n        new EagerInitializedSingleton();\n    \n    private EagerInitializedSingleton() { }\n    \n    public static EagerInitializedSingleton getInstance() {\n        return instance;\n    }\n}\n
\n

Reasoning: Instance created when class is loaded. Thread-safe by default but allocates memory immediately.

\n

2. Lazy Initialization with Synchronization

\n
public class ThreadSafeSingleton {\n    private static ThreadSafeSingleton instance;\n    \n    private ThreadSafeSingleton() { }\n    \n    public static synchronized ThreadSafeSingleton getInstance() {\n        if (instance == null) {\n            instance = new ThreadSafeSingleton();\n        }\n        return instance;\n    }\n}\n
\n

Reasoning: Creates instance on first use. Synchronized method ensures thread-safety but causes synchronization overhead on every call.

\n

3. Double-Checked Locking

\n
public class ThreadSafeSingleton {\n    private static ThreadSafeSingleton instance;\n    \n    private ThreadSafeSingleton() { }\n    \n    public static ThreadSafeSingleton getInstance() {\n        if (instance == null) {\n            synchronized (ThreadSafeSingleton.class) {\n                if (instance == null) {\n                    instance = new ThreadSafeSingleton();\n                }\n            }\n        }\n        return instance;\n    }\n}\n
\n

Reasoning: Checks instance twice—once outside lock, once inside. Reduces synchronization overhead while ensuring thread-safety.

\n

4. Bill Pugh Singleton (Class Loader)

\n
public class BillPughSingleton {\n    private BillPughSingleton() { }\n    \n    private static class SingletonHelper {\n        private static final BillPughSingleton instance = \n            new BillPughSingleton();\n    }\n    \n    public static BillPughSingleton getInstance() {\n        return SingletonHelper.instance;\n    }\n}\n
\n

Reasoning: Uses inner class to achieve lazy initialization. Thread-safe by design and efficient (no synchronization overhead).

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Singleton {\n        -static instance: Singleton\n        +getInstance(): Singleton\n    }\n    Client --> Singleton\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Singleton: getInstance()\n    Singleton-->>Client: instance\n
\n
\n

🔀 Design Principles Emphasized

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
PrincipleHow Applied
Single ResponsibilitySingleton class has one job: manage the single instance
Dependency InversionClients depend on the abstraction (interface) rather than concrete class
Separation of ConcernsInstance management is separated from business logic
Composition over InheritanceRather than subclassing, dependency is injected or accessed via static method
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Global Access: Provides easy, centralized access to shared resource
  • \n
  • Controlled Instantiation: Guarantees exactly one instance exists
  • \n
  • Lazy Initialization (Option Dependent): Defers object creation until needed
  • \n
  • Memory Efficient: Only one instance in memory
  • \n
  • Thread-Safe (Option Dependent): Several implementations are inherently thread-safe
  • \n
\n

Disadvantages ❌

\n
    \n
  • Testing Difficulty: Hard to mock for unit tests; global state complicates testing
  • \n
  • Hidden Dependencies: Not obvious that code depends on a singleton; dependencies are implicit
  • \n
  • Synchronization Overhead: Lock-based implementations add performance cost
  • \n
  • Violates Single Responsibility: Often handles both instantiation and business logic
  • \n
  • Rigid: Extending or replacing the singleton is difficult without modifying client code
  • \n
  • Global State: Makes code less predictable and harder to reason about
  • \n
  • Concurrency Issues: Some implementations (eager loading) may fail under specific multi-threaded scenarios
  • \n
\n
\n

🚫 When NOT to Use

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ScenarioWhy Avoid
Stateful ObjectsSharing state across all clients leads to unexpected side effects
Testable SystemsGlobal dependencies make unit testing extremely difficult
Multiple Instances NeededIf business logic later requires multiple instances, refactoring is painful
Distributed SystemsEach JVM/process gets its own instance; doesn’t guarantee global uniqueness
Simple ServicesDependency Injection (DI) containers provide same benefits with better flexibility
\n
\n

⚠️ Common Anti-Patterns & Misuses

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Anti-PatternProblemSolution
Mutable SingletonShared state gets corrupted by concurrent modificationsMake singleton immutable or use thread-safe collections
Singleton as Service LocatorHides dependencies and couples code to singletonUse constructor injection instead
Testing Without Mock/SpyTests affect each other via shared stateProvide reset method or use test-specific implementations
Singleton InheritanceEach subclass becomes a different singletonUse composition; wrap the actual singleton
Unnecessary SingletonsOver-use creates tight couplingPrefer dependency injection via constructors
Non-Thread-Safe SingletonRace conditions in multi-threaded appsUse double-checked locking or eager initialization
\n
\n

🌍 Real-World Use Cases

\n

Spring Framework

\n
// Spring beans are singletons by default\n@Service\npublic class UserService {\n    // Only one instance in Spring Container\n}\n\n// Access via Dependency Injection\n@Component\npublic class UserController {\n    @Autowired\n    private UserService userService;  // Singleton instance injected\n}\n
\n

Log4j / SLF4J

\n
// Logger is typically a singleton\nLogger logger = LoggerFactory.getLogger(MyClass.class);\n// Returns same logger instance for same class name\n
\n

Database Connection Pool

\n
// ConnectionPool as singleton to manage all connections\npublic class ConnectionPool {\n    private static final ConnectionPool instance = new ConnectionPool();\n    \n    public static ConnectionPool getInstance() {\n        return instance;\n    }\n}\n
\n

Configuration Manager

\n
// Singleton holding application configuration\npublic class AppConfig {\n    private static final AppConfig instance = new AppConfig();\n    \n    public String getDatabaseUrl() { /* ... */ }\n    public int getMaxConnections() { /* ... */ }\n}\n
\n
\n

🔗 Alternatives & Similar Patterns

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AlternativeWhen to Prefer
Dependency InjectionWhen using a DI container (Spring, Guice); provides testability and flexibility
Static ClassFor stateless utilities; simpler than singleton but can’t implement interfaces
Enum SingletonFor thread-safety and serialization guarantees in Java
Factory PatternWhen you need flexibility to create different implementations
Service LocatorWhen you need dynamic service registration (though often considered an anti-pattern)
\n
\n

📝 Best Practices

\n
    \n
  1. Prefer Dependency Injection: Use DI container (Spring, Guice) instead of manual singleton management
  2. \n
  3. Make Thread-Safe: Use Bill Pugh Singleton or eager initialization for multi-threaded applications
  4. \n
  5. Document Constraints: Clearly state that your class is a singleton and why
  6. \n
  7. Provide Test Hooks: Add methods to reset state for testing
  8. \n
  9. Avoid Mutable State: Keep singleton data immutable or use thread-safe collections
  10. \n
  11. Consider Enum Singleton: In Java, enum provides the most robust singleton implementation
  12. \n
  13. Avoid as Service Locator: Don’t use singleton to hide dependencies; use dependency injection
  14. \n
\n
\n

🎓 Related Patterns

\n
    \n
  • Factory Pattern: Often works with Singleton to control creation
  • \n
  • Lazy Initialization: Deferring object creation until first use
  • \n
  • Builder Pattern: Can be used to construct complex singleton objects
  • \n
  • Object Pool Pattern: Similar in controlling limited resources
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Effective Java (Joshua Bloch)
  • \n
  • Spring Framework Singleton Scope
  • \n
  • Enum as Singleton in Java
  • \n
\n", + "contentMarkdown": "# Singleton Pattern\n\n## 📋 Overview\n\nThe **Singleton Pattern** ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to access that instance universally.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- You need to guarantee that only one instance of a class exists throughout the application lifecycle\n- Multiple instances would cause logical errors or resource conflicts (e.g., database connections, configuration managers, logging services)\n- You need a globally accessible point of access to this single instance without passing references through all layers\n\n**Use When:**\n- You need a single, shared resource manager (connection pools, thread pools, caches)\n- You need a centralized configuration holder or registry\n- You need exactly one instance of a service to coordinate system-wide activities\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| **Singleton** | Ensures only one instance exists via private constructor; provides static method to access the single instance |\n| **Client** | Accesses the singleton instance through the public static accessor method |\n\n**Key Characteristics:**\n- Private constructor prevents external instantiation\n- Static instance variable holds the single object\n- Public static accessor method (`getInstance()`) returns the instance\n- Thread-safety considerations for multi-threaded environments\n\n---\n\n## 💡 Implementation Strategies\n\nThis pattern has multiple implementations, each with different trade-offs:\n\n### 1. **Eager Initialization**\n```java\npublic class EagerInitializedSingleton {\n private static final EagerInitializedSingleton instance = \n new EagerInitializedSingleton();\n \n private EagerInitializedSingleton() { }\n \n public static EagerInitializedSingleton getInstance() {\n return instance;\n }\n}\n```\n**Reasoning:** Instance created when class is loaded. Thread-safe by default but allocates memory immediately.\n\n### 2. **Lazy Initialization with Synchronization**\n```java\npublic class ThreadSafeSingleton {\n private static ThreadSafeSingleton instance;\n \n private ThreadSafeSingleton() { }\n \n public static synchronized ThreadSafeSingleton getInstance() {\n if (instance == null) {\n instance = new ThreadSafeSingleton();\n }\n return instance;\n }\n}\n```\n**Reasoning:** Creates instance on first use. Synchronized method ensures thread-safety but causes synchronization overhead on every call.\n\n### 3. **Double-Checked Locking**\n```java\npublic class ThreadSafeSingleton {\n private static ThreadSafeSingleton instance;\n \n private ThreadSafeSingleton() { }\n \n public static ThreadSafeSingleton getInstance() {\n if (instance == null) {\n synchronized (ThreadSafeSingleton.class) {\n if (instance == null) {\n instance = new ThreadSafeSingleton();\n }\n }\n }\n return instance;\n }\n}\n```\n**Reasoning:** Checks instance twice—once outside lock, once inside. Reduces synchronization overhead while ensuring thread-safety.\n\n### 4. **Bill Pugh Singleton (Class Loader)**\n```java\npublic class BillPughSingleton {\n private BillPughSingleton() { }\n \n private static class SingletonHelper {\n private static final BillPughSingleton instance = \n new BillPughSingleton();\n }\n \n public static BillPughSingleton getInstance() {\n return SingletonHelper.instance;\n }\n}\n```\n**Reasoning:** Uses inner class to achieve lazy initialization. Thread-safe by design and efficient (no synchronization overhead).\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Singleton {\n -static instance: Singleton\n +getInstance(): Singleton\n }\n Client --> Singleton\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Singleton: getInstance()\n Singleton-->>Client: instance\n```\n\n---\n\n## 🔀 Design Principles Emphasized\n\n| Principle | How Applied |\n|-----------|------------|\n| **Single Responsibility** | Singleton class has one job: manage the single instance |\n| **Dependency Inversion** | Clients depend on the abstraction (interface) rather than concrete class |\n| **Separation of Concerns** | Instance management is separated from business logic |\n| **Composition over Inheritance** | Rather than subclassing, dependency is injected or accessed via static method |\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- **Global Access:** Provides easy, centralized access to shared resource\n- **Controlled Instantiation:** Guarantees exactly one instance exists\n- **Lazy Initialization (Option Dependent):** Defers object creation until needed\n- **Memory Efficient:** Only one instance in memory\n- **Thread-Safe (Option Dependent):** Several implementations are inherently thread-safe\n\n### Disadvantages ❌\n- **Testing Difficulty:** Hard to mock for unit tests; global state complicates testing\n- **Hidden Dependencies:** Not obvious that code depends on a singleton; dependencies are implicit\n- **Synchronization Overhead:** Lock-based implementations add performance cost\n- **Violates Single Responsibility:** Often handles both instantiation and business logic\n- **Rigid:** Extending or replacing the singleton is difficult without modifying client code\n- **Global State:** Makes code less predictable and harder to reason about\n- **Concurrency Issues:** Some implementations (eager loading) may fail under specific multi-threaded scenarios\n\n---\n\n## 🚫 When NOT to Use\n\n| Scenario | Why Avoid |\n|----------|-----------|\n| **Stateful Objects** | Sharing state across all clients leads to unexpected side effects |\n| **Testable Systems** | Global dependencies make unit testing extremely difficult |\n| **Multiple Instances Needed** | If business logic later requires multiple instances, refactoring is painful |\n| **Distributed Systems** | Each JVM/process gets its own instance; doesn't guarantee global uniqueness |\n| **Simple Services** | Dependency Injection (DI) containers provide same benefits with better flexibility |\n\n---\n\n## ⚠️ Common Anti-Patterns & Misuses\n\n| Anti-Pattern | Problem | Solution |\n|--------------|---------|----------|\n| **Mutable Singleton** | Shared state gets corrupted by concurrent modifications | Make singleton immutable or use thread-safe collections |\n| **Singleton as Service Locator** | Hides dependencies and couples code to singleton | Use constructor injection instead |\n| **Testing Without Mock/Spy** | Tests affect each other via shared state | Provide reset method or use test-specific implementations |\n| **Singleton Inheritance** | Each subclass becomes a different singleton | Use composition; wrap the actual singleton |\n| **Unnecessary Singletons** | Over-use creates tight coupling | Prefer dependency injection via constructors |\n| **Non-Thread-Safe Singleton** | Race conditions in multi-threaded apps | Use double-checked locking or eager initialization |\n\n---\n\n## 🌍 Real-World Use Cases\n\n### Spring Framework\n```java\n// Spring beans are singletons by default\n@Service\npublic class UserService {\n // Only one instance in Spring Container\n}\n\n// Access via Dependency Injection\n@Component\npublic class UserController {\n @Autowired\n private UserService userService; // Singleton instance injected\n}\n```\n\n### Log4j / SLF4J\n```java\n// Logger is typically a singleton\nLogger logger = LoggerFactory.getLogger(MyClass.class);\n// Returns same logger instance for same class name\n```\n\n### Database Connection Pool\n```java\n// ConnectionPool as singleton to manage all connections\npublic class ConnectionPool {\n private static final ConnectionPool instance = new ConnectionPool();\n \n public static ConnectionPool getInstance() {\n return instance;\n }\n}\n```\n\n### Configuration Manager\n```java\n// Singleton holding application configuration\npublic class AppConfig {\n private static final AppConfig instance = new AppConfig();\n \n public String getDatabaseUrl() { /* ... */ }\n public int getMaxConnections() { /* ... */ }\n}\n```\n\n---\n\n## 🔗 Alternatives & Similar Patterns\n\n| Alternative | When to Prefer |\n|-------------|-----------------|\n| **Dependency Injection** | When using a DI container (Spring, Guice); provides testability and flexibility |\n| **Static Class** | For stateless utilities; simpler than singleton but can't implement interfaces |\n| **Enum Singleton** | For thread-safety and serialization guarantees in Java |\n| **Factory Pattern** | When you need flexibility to create different implementations |\n| **Service Locator** | When you need dynamic service registration (though often considered an anti-pattern) |\n\n---\n\n## 📝 Best Practices\n\n1. **Prefer Dependency Injection:** Use DI container (Spring, Guice) instead of manual singleton management\n2. **Make Thread-Safe:** Use Bill Pugh Singleton or eager initialization for multi-threaded applications\n3. **Document Constraints:** Clearly state that your class is a singleton and why\n4. **Provide Test Hooks:** Add methods to reset state for testing\n5. **Avoid Mutable State:** Keep singleton data immutable or use thread-safe collections\n6. **Consider Enum Singleton:** In Java, `enum` provides the most robust singleton implementation\n7. **Avoid as Service Locator:** Don't use singleton to hide dependencies; use dependency injection\n\n---\n\n## 🎓 Related Patterns\n\n- **Factory Pattern:** Often works with Singleton to control creation\n- **Lazy Initialization:** Deferring object creation until first use\n- **Builder Pattern:** Can be used to construct complex singleton objects\n- **Object Pool Pattern:** Similar in controlling limited resources\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Effective Java (Joshua Bloch)\n- Spring Framework Singleton Scope\n- Enum as Singleton in Java", + "relatedPatternIds": [ + "builder", + "factory-method", + "abstract-factory", + "prototype" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation Strategies", + "1. **Eager Initialization**", + "2. **Lazy Initialization with Synchronization**", + "3. **Double-Checked Locking**", + "4. **Bill Pugh Singleton (Class Loader)**", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🔀 Design Principles Emphasized", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "⚠️ Common Anti-Patterns & Misuses", + "🌍 Real-World Use Cases", + "Spring Framework", + "Log4j / SLF4J", + "Database Connection Pool", + "Configuration Manager", + "🔗 Alternatives & Similar Patterns", + "📝 Best Practices", + "🎓 Related Patterns", + "📚 References" + ], + "excerpt": "Singleton Pattern 📋 Overview The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. This is a creational pattern that restricts object instantiation to a single instance while providing a mechanism to acc", + "featured": false + }, + { + "id": "state", + "slug": "state", + "name": "State", + "category": "gof", + "subcategory": "behavioral", + "summary": "The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.", + "intent": "The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "State", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "allows", + "object", + "alter", + "its", + "behavior", + "when", + "internal", + "changes", + "will", + "appear", + "change", + "class", + "state transitions", + "state-driven behavior" + ], + "aliases": [ + "state" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/state", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/state", + "demoCodePaths": [ + "gof-patterns/state/src/main/java", + "gof-patterns/state/src/main", + "gof-patterns/state/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

State Pattern

\n

📋 Overview

\n

The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Object behavior varies based on state
  • \n
  • Large conditional statements checking state
  • \n
  • State transitions need management
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ContextDefines interface, delegates to State
StateDefines interface for state-specific behavior
ConcreteStateImplements state-specific behavior
\n
\n

💡 Code Example

\n
public interface State {\n    void handle(Context context);\n}\n\npublic class Context {\n    private State state;\n    \n    public Context(State state) {\n        this.state = state;\n    }\n    \n    public void setState(State state) {\n        this.state = state;\n    }\n    \n    public void request() {\n        state.handle(this);\n    }\n}\n\npublic class ConcreteStateA implements State {\n    @Override\n    public void handle(Context context) {\n        System.out.println("State A handling");\n        context.setState(new ConcreteStateB());\n    }\n}\n\n// Usage\nContext context = new Context(new ConcreteStateA());\ncontext.request();\ncontext.request();\n
\n

Reasoning: Encapsulates state-dependent behavior; enables state-specific transitions.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Context {\n        -state: State\n        +request()\n        +setState(s: State)\n    }\n    class State {\n        <<interface>>\n        +handle(ctx: Context)\n    }\n    class ConcreteStateA\n    class ConcreteStateB\n    Context --> State\n    State <|-- ConcreteStateA\n    State <|-- ConcreteStateB\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Context: request()\n    Context->>State: handle(context)\n    State-->>Context: maybe change state\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Eliminates large conditional statements
  • \n
  • Localizes state-specific behavior
  • \n
  • Easy to add new states
  • \n
  • State transitions explicit
  • \n
  • Supports complex state machines
  • \n
\n

Disadvantages ❌

\n
    \n
  • Increased number of classes
  • \n
  • More complex than simple conditionals
  • \n
  • State dependency coupling
  • \n
  • Increased memory usage
  • \n
  • Performance overhead
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Workflow engines
  • \n
  • State machines
  • \n
  • Game object states
  • \n
  • TCP connection states
  • \n
  • Order processing workflows
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • State Machine Design
  • \n
\n", + "contentMarkdown": "# State Pattern\n\n## 📋 Overview\n\nThe **State** pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Object behavior varies based on state\n- Large conditional statements checking state\n- State transitions need management\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Context | Defines interface, delegates to State |\n| State | Defines interface for state-specific behavior |\n| ConcreteState | Implements state-specific behavior |\n\n---\n\n## 💡 Code Example\n\n```java\npublic interface State {\n void handle(Context context);\n}\n\npublic class Context {\n private State state;\n \n public Context(State state) {\n this.state = state;\n }\n \n public void setState(State state) {\n this.state = state;\n }\n \n public void request() {\n state.handle(this);\n }\n}\n\npublic class ConcreteStateA implements State {\n @Override\n public void handle(Context context) {\n System.out.println(\"State A handling\");\n context.setState(new ConcreteStateB());\n }\n}\n\n// Usage\nContext context = new Context(new ConcreteStateA());\ncontext.request();\ncontext.request();\n```\n\n**Reasoning:** Encapsulates state-dependent behavior; enables state-specific transitions.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Context {\n -state: State\n +request()\n +setState(s: State)\n }\n class State {\n <>\n +handle(ctx: Context)\n }\n class ConcreteStateA\n class ConcreteStateB\n Context --> State\n State <|-- ConcreteStateA\n State <|-- ConcreteStateB\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Context: request()\n Context->>State: handle(context)\n State-->>Context: maybe change state\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Eliminates large conditional statements\n- Localizes state-specific behavior\n- Easy to add new states\n- State transitions explicit\n- Supports complex state machines\n\n### Disadvantages ❌\n- Increased number of classes\n- More complex than simple conditionals\n- State dependency coupling\n- Increased memory usage\n- Performance overhead\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Workflow engines\n- State machines\n- Game object states\n- TCP connection states\n- Order processing workflows\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- State Machine Design", + "relatedPatternIds": [ + "observer", + "command", + "template-method", + "chain" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "State Pattern 📋 Overview The State pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. 👥 Roles & Responsibilities Role Responsibility Context Defines interface, delegates to State State ", + "featured": false + }, + { + "id": "strategy", + "slug": "strategy", + "name": "Strategy", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.", + "intent": "The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Strategy", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "defines", + "family", + "algorithms", + "encapsulates", + "each", + "one", + "and", + "makes", + "them", + "interchangeable" + ], + "aliases": [ + "strategy" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/strategy", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/strategy", + "demoCodePaths": [ + "gof-patterns/strategy/src/main/java", + "gof-patterns/strategy/src/main", + "gof-patterns/strategy/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Strategy Pattern

\n

📋 Overview

\n

The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Multiple algorithms for a task
  • \n
  • Algorithm selection varies
  • \n
  • Avoid large conditional statements
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
StrategyDefines interface for algorithm
ConcreteStrategyImplements specific algorithm
ContextUses Strategy
\n
\n

💡 Code Example

\n
public interface SortStrategy {\n    void sort(int[] array);\n}\n\npublic class Context {\n    private SortStrategy strategy;\n    \n    public void setStrategy(SortStrategy strategy) {\n        this.strategy = strategy;\n    }\n    \n    public void executeSort(int[] array) {\n        strategy.sort(array);\n    }\n}\n\npublic class QuickSort implements SortStrategy {\n    @Override\n    public void sort(int[] array) {\n        // QuickSort implementation\n    }\n}\n\n// Usage\nContext context = new Context();\ncontext.setStrategy(new QuickSort());\ncontext.executeSort(array);\n
\n

Reasoning: Encapsulates algorithms; enables runtime selection; promotes composition.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Context {\n        -strategy: Strategy\n        +setStrategy(s: Strategy)\n        +execute()\n    }\n    class Strategy {\n        <<interface>>\n        +algorithm()\n    }\n    class ConcreteStrategyA\n    class ConcreteStrategyB\n    Context --> Strategy\n    Strategy <|-- ConcreteStrategyA\n    Strategy <|-- ConcreteStrategyB\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Context: setStrategy(strategy)\n    Client->>Context: execute()\n    Context->>Strategy: algorithm()\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Encapsulates algorithms
  • \n
  • Runtime algorithm selection
  • \n
  • Eliminates conditionals
  • \n
  • Promotes composition
  • \n
  • Easy to add new strategies
  • \n
\n

Disadvantages ❌

\n
    \n
  • Increased number of classes
  • \n
  • Overhead for simple algorithms
  • \n
  • Client must understand strategies
  • \n
  • Context-strategy coupling
  • \n
  • Strategy selection complexity
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Payment methods
  • \n
  • Compression algorithms
  • \n
  • Sorting algorithms
  • \n
  • Search strategies
  • \n
  • Rendering engines
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Algorithm encapsulation
  • \n
\n", + "contentMarkdown": "# Strategy Pattern\n\n## 📋 Overview\n\nThe **Strategy** pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Multiple algorithms for a task\n- Algorithm selection varies\n- Avoid large conditional statements\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Strategy | Defines interface for algorithm |\n| ConcreteStrategy | Implements specific algorithm |\n| Context | Uses Strategy |\n\n---\n\n## 💡 Code Example\n\n```java\npublic interface SortStrategy {\n void sort(int[] array);\n}\n\npublic class Context {\n private SortStrategy strategy;\n \n public void setStrategy(SortStrategy strategy) {\n this.strategy = strategy;\n }\n \n public void executeSort(int[] array) {\n strategy.sort(array);\n }\n}\n\npublic class QuickSort implements SortStrategy {\n @Override\n public void sort(int[] array) {\n // QuickSort implementation\n }\n}\n\n// Usage\nContext context = new Context();\ncontext.setStrategy(new QuickSort());\ncontext.executeSort(array);\n```\n\n**Reasoning:** Encapsulates algorithms; enables runtime selection; promotes composition.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Context {\n -strategy: Strategy\n +setStrategy(s: Strategy)\n +execute()\n }\n class Strategy {\n <>\n +algorithm()\n }\n class ConcreteStrategyA\n class ConcreteStrategyB\n Context --> Strategy\n Strategy <|-- ConcreteStrategyA\n Strategy <|-- ConcreteStrategyB\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Context: setStrategy(strategy)\n Client->>Context: execute()\n Context->>Strategy: algorithm()\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Encapsulates algorithms\n- Runtime algorithm selection\n- Eliminates conditionals\n- Promotes composition\n- Easy to add new strategies\n\n### Disadvantages ❌\n- Increased number of classes\n- Overhead for simple algorithms\n- Client must understand strategies\n- Context-strategy coupling\n- Strategy selection complexity\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Payment methods\n- Compression algorithms\n- Sorting algorithms\n- Search strategies\n- Rendering engines\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Algorithm encapsulation", + "relatedPatternIds": [ + "command", + "observer", + "template-method", + "mediator" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Strategy Pattern 📋 Overview The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. 👥 Roles & Responsibilities Role Responsibility Strategy Defines interface for algorithm ConcreteStrategy Implements specif", + "featured": false + }, + { + "id": "template-method", + "slug": "template-method", + "name": "Template Method", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.", + "intent": "The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Template Method", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Template", + "Method", + "pattern", + "defines", + "skeleton", + "algorithm", + "base", + "class", + "letting", + "subclasses", + "override", + "specific", + "steps" + ], + "aliases": [ + "template method" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/template-method", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/template-method", + "demoCodePaths": [ + "gof-patterns/template-method/src/main/java", + "gof-patterns/template-method/src/main", + "gof-patterns/template-method/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Template Method Pattern

\n

📋 Overview

\n

The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Algorithm structure is fixed, but steps vary
  • \n
  • Avoid code duplication in algorithm implementations
  • \n
  • Control subclass overrides
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
AbstractClassDefines template method and steps
ConcreteClassImplements specific steps
\n
\n

💡 Code Example

\n
public abstract class DataProcessor {\n    public final void process() {\n        readData();\n        validateData();\n        processData();\n        writeData();\n    }\n    \n    abstract void readData();\n    abstract void validateData();\n    abstract void processData();\n    abstract void writeData();\n}\n\npublic class XMLProcessor extends DataProcessor {\n    @Override\n    void readData() { /* XML reading */ }\n    \n    @Override\n    void validateData() { /* XML validation */ }\n    \n    @Override\n    void processData() { /* XML processing */ }\n    \n    @Override\n    void writeData() { /* XML writing */ }\n}\n\n// Usage\nDataProcessor processor = new XMLProcessor();\nprocessor.process();\n
\n

Reasoning: Defines algorithm structure; lets subclasses implement steps; prevents duplication.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class AbstractClass {\n        +templateMethod()\n        #primitiveOp1()\n        #primitiveOp2()\n    }\n    class ConcreteClass\n    AbstractClass <|-- ConcreteClass\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>AbstractClass: templateMethod()\n    AbstractClass->>AbstractClass: primitiveOp1()\n    AbstractClass->>AbstractClass: primitiveOp2()\n    AbstractClass-->>Client: done\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Code reuse
  • \n
  • Controls extension points
  • \n
  • Defines skeleton once
  • \n
  • Consistent algorithm structure
  • \n
  • Promotes inheritance
  • \n
\n

Disadvantages ❌

\n
    \n
  • Inheritance hierarchy required
  • \n
  • Tight coupling between base and derived
  • \n
  • Hollywood Principle violation possible
  • \n
  • Inflexible for diverse algorithms
  • \n
  • Violates Composition over Inheritance
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Framework hook methods
  • \n
  • Stream processing pipelines
  • \n
  • Database connection pooling
  • \n
  • Junit test setup/teardown
  • \n
  • Application lifecycle methods
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Template Method variations
  • \n
\n", + "contentMarkdown": "# Template Method Pattern\n\n## 📋 Overview\n\nThe **Template Method** pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Algorithm structure is fixed, but steps vary\n- Avoid code duplication in algorithm implementations\n- Control subclass overrides\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| AbstractClass | Defines template method and steps |\n| ConcreteClass | Implements specific steps |\n\n---\n\n## 💡 Code Example\n\n```java\npublic abstract class DataProcessor {\n public final void process() {\n readData();\n validateData();\n processData();\n writeData();\n }\n \n abstract void readData();\n abstract void validateData();\n abstract void processData();\n abstract void writeData();\n}\n\npublic class XMLProcessor extends DataProcessor {\n @Override\n void readData() { /* XML reading */ }\n \n @Override\n void validateData() { /* XML validation */ }\n \n @Override\n void processData() { /* XML processing */ }\n \n @Override\n void writeData() { /* XML writing */ }\n}\n\n// Usage\nDataProcessor processor = new XMLProcessor();\nprocessor.process();\n```\n\n**Reasoning:** Defines algorithm structure; lets subclasses implement steps; prevents duplication.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class AbstractClass {\n +templateMethod()\n #primitiveOp1()\n #primitiveOp2()\n }\n class ConcreteClass\n AbstractClass <|-- ConcreteClass\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>AbstractClass: templateMethod()\n AbstractClass->>AbstractClass: primitiveOp1()\n AbstractClass->>AbstractClass: primitiveOp2()\n AbstractClass-->>Client: done\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Code reuse\n- Controls extension points\n- Defines skeleton once\n- Consistent algorithm structure\n- Promotes inheritance\n\n### Disadvantages ❌\n- Inheritance hierarchy required\n- Tight coupling between base and derived\n- Hollywood Principle violation possible\n- Inflexible for diverse algorithms\n- Violates Composition over Inheritance\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Framework hook methods\n- Stream processing pipelines\n- Database connection pooling\n- Junit test setup/teardown\n- Application lifecycle methods\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Template Method variations", + "relatedPatternIds": [ + "observer", + "state", + "strategy", + "chain" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Template Method Pattern 📋 Overview The Template Method pattern defines the skeleton of an algorithm in a base class, letting subclasses override specific steps. 👥 Roles & Responsibilities Role Responsibility AbstractClass Defines template method and steps Co", + "featured": false + }, + { + "id": "visitor", + "slug": "visitor", + "name": "Visitor", + "category": "gof", + "subcategory": "behavioral", + "summary": "The Visitor pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.", + "intent": "The Visitor pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Visitor", + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "represents", + "operation", + "performed", + "elements", + "object", + "structure", + "lets", + "you", + "define", + "new", + "without", + "changing", + "classes", + "which", + "operates" + ], + "aliases": [ + "visitor" + ], + "tags": [ + "gof", + "behavioral", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "gof-patterns/visitor", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/gof-patterns/visitor", + "demoCodePaths": [ + "gof-patterns/visitor/src/main/java", + "gof-patterns/visitor/src/main", + "gof-patterns/visitor/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Visitor Pattern

\n

📋 Overview

\n

The Visitor pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Perform operations on complex object structures without changing their classes
  • \n
  • Add new operations to class hierarchy without modification
  • \n
  • Operations are related but scattered across classes
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
VisitorDeclares visit methods for each element type
ConcreteVisitorImplements specific operations
ElementAccepts visitor
ConcreteElementImplements accept method
ObjectStructureProvides access to elements
\n
\n

💡 Implementation

\n

Visitor pattern is particularly useful when you have:

\n
    \n
  • Complex object hierarchies requiring multiple operations
  • \n
  • Operations that change frequently
  • \n
  • Classes that shouldn’t be modified with new methods
  • \n
  • Need to gather data from object structure
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Visitor {\n        <<interface>>\n        +visitConcreteElementA(e)\n        +visitConcreteElementB(e)\n    }\n    class ConcreteVisitor\n    class Element {\n        <<interface>>\n        +accept(v: Visitor)\n    }\n    class ConcreteElementA\n    class ConcreteElementB\n    Visitor <|-- ConcreteVisitor\n    Element <|-- ConcreteElementA\n    Element <|-- ConcreteElementB\n    Element --> Visitor\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Element: accept(visitor)\n    Element->>Visitor: visit(element)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Separates operations from objects
  • \n
  • Easy to add new operations
  • \n
  • Gathers related operations
  • \n
  • Follows Open/Closed Principle
  • \n
  • Centralizes operation logic
  • \n
\n

Disadvantages ❌

\n
    \n
  • Difficult to add new element types
  • \n
  • Violates Encapsulation
  • \n
  • Double dispatch complexity
  • \n
  • Hard to understand
  • \n
  • Multiple pass traversals
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Compiler AST visitors
  • \n
  • Document processors
  • \n
  • Report generators
  • \n
  • Tree structure operations
  • \n
  • Metrics collection tools
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Compiler design patterns
  • \n
\n", + "contentMarkdown": "# Visitor Pattern\n\n## 📋 Overview\n\nThe **Visitor** pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Perform operations on complex object structures without changing their classes\n- Add new operations to class hierarchy without modification\n- Operations are related but scattered across classes\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Visitor | Declares visit methods for each element type |\n| ConcreteVisitor | Implements specific operations |\n| Element | Accepts visitor |\n| ConcreteElement | Implements accept method |\n| ObjectStructure | Provides access to elements |\n\n---\n\n## 💡 Implementation\n\nVisitor pattern is particularly useful when you have:\n- Complex object hierarchies requiring multiple operations\n- Operations that change frequently\n- Classes that shouldn't be modified with new methods\n- Need to gather data from object structure\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Visitor {\n <>\n +visitConcreteElementA(e)\n +visitConcreteElementB(e)\n }\n class ConcreteVisitor\n class Element {\n <>\n +accept(v: Visitor)\n }\n class ConcreteElementA\n class ConcreteElementB\n Visitor <|-- ConcreteVisitor\n Element <|-- ConcreteElementA\n Element <|-- ConcreteElementB\n Element --> Visitor\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Element: accept(visitor)\n Element->>Visitor: visit(element)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Separates operations from objects\n- Easy to add new operations\n- Gathers related operations\n- Follows Open/Closed Principle\n- Centralizes operation logic\n\n### Disadvantages ❌\n- Difficult to add new element types\n- Violates Encapsulation\n- Double dispatch complexity\n- Hard to understand\n- Multiple pass traversals\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Compiler AST visitors\n- Document processors\n- Report generators\n- Tree structure operations\n- Metrics collection tools\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Compiler design patterns", + "relatedPatternIds": [ + "mediator", + "iterator", + "memento", + "interpreter" + ], + "categoryLabel": "GoF", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Visitor Pattern 📋 Overview The Visitor pattern represents an operation to be performed on elements of an object structure. It lets you define a new operation without changing the classes of the elements on which it operates. 👥 Roles & Responsibilities Role R", + "featured": false + }, + { + "id": "model-view-presenter", + "slug": "model-view-presenter", + "name": "Model-View-Presenter", + "category": "architectural", + "summary": "The Model View Presenter (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model.", + "intent": "The Model View Presenter (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Model-View-Presenter", + "architectural", + "model view presenter", + "MVP", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Model", + "View", + "Presenter", + "pattern", + "separates", + "presentation", + "logic", + "from", + "business", + "introducing", + "component", + "that", + "mediates", + "between", + "and" + ], + "aliases": [ + "model view presenter", + "Model-View-Presenter", + "MVP" + ], + "tags": [ + "architectural", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "architectural-patterns/model-view-presenter", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/architectural-patterns/model-view-presenter", + "demoCodePaths": [ + "architectural-patterns/model-view-presenter/src/main/java", + "architectural-patterns/model-view-presenter/src/main", + "architectural-patterns/model-view-presenter/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Model-View-Presenter Pattern

\n

📋 Overview

\n

The Model-View-Presenter (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Separate UI from business logic
  • \n
  • Make UI components testable
  • \n
  • Enable code reuse across UI frameworks
  • \n
  • Improve maintainability of UI code
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ModelBusiness logic and data
ViewDisplays data, handles user interaction
PresenterCoordinates Model and View
\n
\n

💡 Implementation

\n
    \n
  • View is passive (no business logic)
  • \n
  • Presenter handles all UI logic
  • \n
  • Model remains UI-independent
  • \n
  • MVP enables testing without UI framework
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Model\n    class View {\n        <<interface>>\n        +render(data)\n    }\n    class Presenter {\n        -model: Model\n        -view: View\n        +onViewEvent()\n    }\n    class ConcreteView\n    View <|-- ConcreteView\n    Presenter --> Model\n    Presenter --> View\n    ConcreteView --> Presenter\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor User\n    participant View\n    participant Presenter\n    participant Model\n    User->>View: interact()\n    View->>Presenter: event()\n    Presenter->>Model: update()\n    Model-->>Presenter: data\n    Presenter->>View: render(data)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Clear separation of concerns
  • \n
  • Testable UI logic
  • \n
  • Reusable presenters
  • \n
  • Framework independence
  • \n
  • Flexible UI
  • \n
\n

Disadvantages ❌

\n
    \n
  • More classes and complexity
  • \n
  • Boilerplate code
  • \n
  • Learning curve
  • \n
  • Performance overhead
  • \n
  • Over-engineering for simple UIs
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Android applications
  • \n
  • Desktop GUI applications
  • \n
  • Web application presenters
  • \n
  • Testing UI behavior
  • \n
  • Multi-platform applications
  • \n
\n
\n

📚 References

\n
    \n
  • MVP architecture
  • \n
  • Martin Fowler MVP article
  • \n
  • Android MVP pattern
  • \n
\n", + "contentMarkdown": "# Model-View-Presenter Pattern\n\n## 📋 Overview\n\nThe **Model-View-Presenter** (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Separate UI from business logic\n- Make UI components testable\n- Enable code reuse across UI frameworks\n- Improve maintainability of UI code\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Model | Business logic and data |\n| View | Displays data, handles user interaction |\n| Presenter | Coordinates Model and View |\n\n---\n\n## 💡 Implementation\n\n- View is passive (no business logic)\n- Presenter handles all UI logic\n- Model remains UI-independent\n- MVP enables testing without UI framework\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Model\n class View {\n <>\n +render(data)\n }\n class Presenter {\n -model: Model\n -view: View\n +onViewEvent()\n }\n class ConcreteView\n View <|-- ConcreteView\n Presenter --> Model\n Presenter --> View\n ConcreteView --> Presenter\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor User\n participant View\n participant Presenter\n participant Model\n User->>View: interact()\n View->>Presenter: event()\n Presenter->>Model: update()\n Model-->>Presenter: data\n Presenter->>View: render(data)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Clear separation of concerns\n- Testable UI logic\n- Reusable presenters\n- Framework independence\n- Flexible UI\n\n### Disadvantages ❌\n- More classes and complexity\n- Boilerplate code\n- Learning curve\n- Performance overhead\n- Over-engineering for simple UIs\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Android applications\n- Desktop GUI applications\n- Web application presenters\n- Testing UI behavior\n- Multi-platform applications\n\n---\n\n## 📚 References\n\n- MVP architecture\n- Martin Fowler MVP article\n- Android MVP pattern", + "relatedPatternIds": [ + "state-machine", + "service-locator", + "mediator", + "interpreter" + ], + "categoryLabel": "Architectural", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Model View Presenter Pattern 📋 Overview The Model View Presenter (MVP) pattern separates presentation logic from business logic by introducing a presenter component that mediates between the view and model. 👥 Roles & Responsibilities Role Responsibility Mode", + "featured": false + }, + { + "id": "service-locator", + "slug": "service-locator", + "name": "Service Locator", + "category": "architectural", + "summary": "The Service Locator pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery.", + "intent": "The Service Locator pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Service Locator", + "architectural", + "overview", + "intent", + "roles responsibilities", + "note", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "⚠️ Note", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Service", + "Locator", + "pattern", + "centralizes", + "logic", + "for", + "creating", + "and", + "accessing", + "services", + "providing", + "single", + "point", + "instantiation", + "discovery" + ], + "aliases": [ + "service locator" + ], + "tags": [ + "architectural", + "overview", + "intent", + "roles responsibilities", + "note", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "architectural-patterns/service-locator", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/architectural-patterns/service-locator", + "demoCodePaths": [ + "architectural-patterns/service-locator/src/main/java", + "architectural-patterns/service-locator/src/main", + "architectural-patterns/service-locator/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Service Locator Pattern

\n

📋 Overview

\n

The Service Locator pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Decouple service creation from usage
  • \n
  • Provide single service access point
  • \n
  • Enable service substitution
  • \n
  • Centralize service configuration
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ServiceLocatorProvides service access
ServiceDefines service interface
ServiceImplConcrete service implementation
\n
\n

⚠️ Note

\n

Service Locator is often considered an anti-pattern. Dependency Injection is the preferred modern approach.

\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class ServiceLocator {\n        +getService(name)\n    }\n    class Service {\n        <<interface>>\n        +execute()\n    }\n    class ConcreteServiceA\n    class ConcreteServiceB\n    Client --> ServiceLocator\n    Service <|-- ConcreteServiceA\n    Service <|-- ConcreteServiceB\n    ServiceLocator --> Service\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>ServiceLocator: getService(name)\n    ServiceLocator-->>Client: Service\n    Client->>Service: execute()\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Centralized service management
  • \n
  • Easy service substitution
  • \n
  • Decouples client from creation
  • \n
  • Dynamic service loading
  • \n
\n

Disadvantages ❌

\n
    \n
  • Hidden dependencies
  • \n
  • Testing complexity
  • \n
  • Global state issues
  • \n
  • Service locator coupling
  • \n
  • Anti-pattern warning
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Legacy application service management
  • \n
  • Plugin systems
  • \n
  • Dynamic service discovery
  • \n
  • Configuration-driven services
  • \n
\n
\n

📚 References

\n
    \n
  • Martin Fowler Service Locator
  • \n
  • Dependency Injection advantages
  • \n
\n", + "contentMarkdown": "# Service Locator Pattern\n\n## 📋 Overview\n\nThe **Service Locator** pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Decouple service creation from usage\n- Provide single service access point\n- Enable service substitution\n- Centralize service configuration\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| ServiceLocator | Provides service access |\n| Service | Defines service interface |\n| ServiceImpl | Concrete service implementation |\n\n---\n\n## ⚠️ Note\n\nService Locator is often considered an anti-pattern. **Dependency Injection** is the preferred modern approach.\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class ServiceLocator {\n +getService(name)\n }\n class Service {\n <>\n +execute()\n }\n class ConcreteServiceA\n class ConcreteServiceB\n Client --> ServiceLocator\n Service <|-- ConcreteServiceA\n Service <|-- ConcreteServiceB\n ServiceLocator --> Service\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>ServiceLocator: getService(name)\n ServiceLocator-->>Client: Service\n Client->>Service: execute()\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Centralized service management\n- Easy service substitution\n- Decouples client from creation\n- Dynamic service loading\n\n### Disadvantages ❌\n- Hidden dependencies\n- Testing complexity\n- Global state issues\n- Service locator coupling\n- Anti-pattern warning\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Legacy application service management\n- Plugin systems\n- Dynamic service discovery\n- Configuration-driven services\n\n---\n\n## 📚 References\n\n- Martin Fowler Service Locator\n- Dependency Injection advantages", + "relatedPatternIds": [ + "model-view-presenter", + "state-machine", + "singleton", + "abstract-factory" + ], + "categoryLabel": "Architectural", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "⚠️ Note", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Service Locator Pattern 📋 Overview The Service Locator pattern centralizes logic for creating and accessing services, providing a single point for service instantiation and discovery. 👥 Roles & Responsibilities Role Responsibility ServiceLocator Provides ser", + "featured": true + }, + { + "id": "state-machine", + "slug": "state-machine", + "name": "State Machine", + "category": "architectural", + "summary": "The State Machine pattern models complex workflows and state transitions using explicit state objects and transitions.", + "intent": "The State Machine pattern models complex workflows and state transitions using explicit state objects and transitions.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "State Machine", + "architectural", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "State", + "Machine", + "pattern", + "models", + "complex", + "workflows", + "and", + "transitions", + "using", + "explicit", + "objects", + "state transitions", + "state-driven behavior" + ], + "aliases": [ + "state machine" + ], + "tags": [ + "architectural", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "architectural-patterns/state-machine", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/architectural-patterns/state-machine", + "demoCodePaths": [ + "architectural-patterns/state-machine/src/main/java", + "architectural-patterns/state-machine/src/main", + "architectural-patterns/state-machine/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

State Machine Pattern

\n

📋 Overview

\n

The State Machine pattern models complex workflows and state transitions using explicit state objects and transitions.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Model complex workflows with multiple states
  • \n
  • Manage state transitions
  • \n
  • Enforce valid state transitions
  • \n
  • Handle state-dependent behavior
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
StateDefines state interface
ConcreteStateImplements state-specific behavior
StateMachineContext managing states
\n
\n

💡 Implementation

\n
    \n
  • States define valid transitions
  • \n
  • Transitions are explicit
  • \n
  • State machine validates transitions
  • \n
  • Prevents invalid state combinations
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class StateMachine {\n        -current: State\n        +handle(event)\n    }\n    class State {\n        <<interface>>\n        +onEvent(event)\n    }\n    class ConcreteStateA\n    class ConcreteStateB\n    class Event\n    StateMachine --> State\n    State <|-- ConcreteStateA\n    State <|-- ConcreteStateB\n    StateMachine --> Event\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>StateMachine: handle(event)\n    StateMachine->>State: onEvent(event)\n    State-->>StateMachine: nextState\n    StateMachine-->>Client: transitioned\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Clear state modeling
  • \n
  • Enforced valid transitions
  • \n
  • Easy to visualize workflow
  • \n
  • Prevents illegal states
  • \n
  • Maintainable complex workflows
  • \n
\n

Disadvantages ❌

\n
    \n
  • Increased complexity
  • \n
  • Many state classes
  • \n
  • Overhead for simple cases
  • \n
  • State explosion risk
  • \n
  • Difficult to modify existing states
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Workflow engines
  • \n
  • Protocol implementations
  • \n
  • Game state management
  • \n
  • Order processing
  • \n
  • TCP connection states
  • \n
\n
\n

📚 References

\n
    \n
  • State Machine design
  • \n
  • Workflow patterns
  • \n
\n", + "contentMarkdown": "# State Machine Pattern\n\n## 📋 Overview\n\nThe **State Machine** pattern models complex workflows and state transitions using explicit state objects and transitions.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Model complex workflows with multiple states\n- Manage state transitions\n- Enforce valid state transitions\n- Handle state-dependent behavior\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| State | Defines state interface |\n| ConcreteState | Implements state-specific behavior |\n| StateMachine | Context managing states |\n\n---\n\n## 💡 Implementation\n\n- States define valid transitions\n- Transitions are explicit\n- State machine validates transitions\n- Prevents invalid state combinations\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class StateMachine {\n -current: State\n +handle(event)\n }\n class State {\n <>\n +onEvent(event)\n }\n class ConcreteStateA\n class ConcreteStateB\n class Event\n StateMachine --> State\n State <|-- ConcreteStateA\n State <|-- ConcreteStateB\n StateMachine --> Event\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>StateMachine: handle(event)\n StateMachine->>State: onEvent(event)\n State-->>StateMachine: nextState\n StateMachine-->>Client: transitioned\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Clear state modeling\n- Enforced valid transitions\n- Easy to visualize workflow\n- Prevents illegal states\n- Maintainable complex workflows\n\n### Disadvantages ❌\n- Increased complexity\n- Many state classes\n- Overhead for simple cases\n- State explosion risk\n- Difficult to modify existing states\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Workflow engines\n- Protocol implementations\n- Game state management\n- Order processing\n- TCP connection states\n\n---\n\n## 📚 References\n\n- State Machine design\n- Workflow patterns", + "relatedPatternIds": [ + "model-view-presenter", + "service-locator", + "filter", + "mediator" + ], + "categoryLabel": "Architectural", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "State Machine Pattern 📋 Overview The State Machine pattern models complex workflows and state transitions using explicit state objects and transitions. 👥 Roles & Responsibilities Role Responsibility State Defines state interface ConcreteState Implements stat", + "featured": false + }, + { + "id": "cqrs", + "slug": "cqrs", + "name": "CQRS Pattern (Command Query Responsibility Segregation)", + "category": "enterprise-integration", + "summary": "CQRS separates the write model (commands) from the read model (queries). Writes typically emit events ; reads are served from a projection optimized for queries.", + "intent": "CQRS separates the write model (commands) from the read model (queries). Writes typically emit events ; reads are served from a projection optimized for queries. An example: player profile writes (rename) emit events; profile reads come from a query store.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "CQRS Pattern (Command Query Responsibility Segregation)", + "enterprise-integration", + "cqrs", + "command query responsibility segregation", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "separates", + "the", + "write", + "model", + "commands", + "from", + "read", + "queries", + "Writes", + "typically", + "emit", + "events", + "reads", + "are", + "served", + "projection", + "optimized", + "for", + "example", + "player", + "profile", + "rename", + "come", + "query", + "store" + ], + "aliases": [ + "cqrs", + "CQRS Pattern (Command Query Responsibility Segregation)", + "command query responsibility segregation" + ], + "tags": [ + "enterprise-integration", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "enterprise-integration-patterns/cqrs", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/enterprise-integration-patterns/cqrs", + "demoCodePaths": [ + "enterprise-integration-patterns/cqrs/src/main/java", + "enterprise-integration-patterns/cqrs/src/main", + "enterprise-integration-patterns/cqrs/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

CQRS Pattern (Command Query Responsibility Segregation)

\n

📋 Overview

\n

CQRS separates the write model (commands) from the read model (queries).\nWrites typically emit events; reads are served from a projection optimized for queries.

\n

An example: player profile writes (rename) emit events; profile reads come from a query store.

\n
\n

🎯 Intent

\n
    \n
  • Scale reads independently from writes
  • \n
  • Keep write-side rules strict while read-side stays fast and flexible
  • \n
  • Enable event-driven projections and eventually consistent read models
  • \n
\n
\n

💡 Code Example

\n
commands.createPlayer("player-42", "RogueMage");\ncommands.changeDisplayName("player-42", "RogueMage_2");\n\nprojector.projectAggregate("player-42");\nvar view = readModel.get("player-42").orElseThrow();\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class PlayerCommandService {\n        +createPlayer(id, name)\n        +changeDisplayName(id, name)\n    }\n    class EventStore {\n        +append(event)\n        +read(aggregateId) List~DomainEvent~\n    }\n    class Projector {\n        +projectAggregate(aggregateId)\n    }\n    class PlayerReadModel {\n        +apply(event)\n        +get(id) PlayerView?\n    }\n    class DomainEvent {\n        <<sealed>>\n        +aggregateId()\n        +occurredAt()\n    }\n    class PlayerCreated\n    class PlayerDisplayNameChanged\n\n    PlayerCommandService --> EventStore : append events\n    Projector --> EventStore : read events\n    Projector --> PlayerReadModel : apply events\n    DomainEvent <|-- PlayerCreated\n    DomainEvent <|-- PlayerDisplayNameChanged\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    participant Cmd as PlayerCommandService\n    participant Store as EventStore\n    participant Proj as Projector\n    participant Read as PlayerReadModel\n\n    Client->>Cmd: changeDisplayName(playerId, newName)\n    Cmd->>Store: append(PlayerDisplayNameChanged)\n    Store-->>Cmd: ok\n\n    Client->>Proj: projectAggregate(playerId)\n    Proj->>Store: read(playerId)\n    Store-->>Proj: events\n    loop events\n        Proj->>Read: apply(event)\n    end\n    Client->>Read: get(playerId)\n    Read-->>Client: PlayerView\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Great for read-heavy systems (leaderboards, profiles)
  • \n
  • Clear separation of concerns
  • \n
  • Works naturally with event sourcing (optional)
  • \n
\n

Disadvantages ❌

\n
    \n
  • Eventual consistency between write and read sides
  • \n
  • Projection code becomes part of your critical path
  • \n
\n", + "contentMarkdown": "# CQRS Pattern (Command Query Responsibility Segregation)\n\n## 📋 Overview\n\n**CQRS** separates the **write model** (commands) from the **read model** (queries).\nWrites typically emit **events**; reads are served from a projection optimized for queries.\n\nAn example: player profile writes (rename) emit events; profile reads come from a query store.\n\n---\n\n## 🎯 Intent\n\n- Scale reads independently from writes\n- Keep write-side rules strict while read-side stays fast and flexible\n- Enable event-driven projections and eventually consistent read models\n\n---\n\n## 💡 Code Example\n\n```java\ncommands.createPlayer(\"player-42\", \"RogueMage\");\ncommands.changeDisplayName(\"player-42\", \"RogueMage_2\");\n\nprojector.projectAggregate(\"player-42\");\nvar view = readModel.get(\"player-42\").orElseThrow();\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class PlayerCommandService {\n +createPlayer(id, name)\n +changeDisplayName(id, name)\n }\n class EventStore {\n +append(event)\n +read(aggregateId) List~DomainEvent~\n }\n class Projector {\n +projectAggregate(aggregateId)\n }\n class PlayerReadModel {\n +apply(event)\n +get(id) PlayerView?\n }\n class DomainEvent {\n <>\n +aggregateId()\n +occurredAt()\n }\n class PlayerCreated\n class PlayerDisplayNameChanged\n\n PlayerCommandService --> EventStore : append events\n Projector --> EventStore : read events\n Projector --> PlayerReadModel : apply events\n DomainEvent <|-- PlayerCreated\n DomainEvent <|-- PlayerDisplayNameChanged\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n participant Cmd as PlayerCommandService\n participant Store as EventStore\n participant Proj as Projector\n participant Read as PlayerReadModel\n\n Client->>Cmd: changeDisplayName(playerId, newName)\n Cmd->>Store: append(PlayerDisplayNameChanged)\n Store-->>Cmd: ok\n\n Client->>Proj: projectAggregate(playerId)\n Proj->>Store: read(playerId)\n Store-->>Proj: events\n loop events\n Proj->>Read: apply(event)\n end\n Client->>Read: get(playerId)\n Read-->>Client: PlayerView\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n\n- Great for read-heavy systems (leaderboards, profiles)\n- Clear separation of concerns\n- Works naturally with event sourcing (optional)\n\n### Disadvantages ❌\n\n- Eventual consistency between write and read sides\n- Projection code becomes part of your critical path", + "relatedPatternIds": [ + "transactional-outbox", + "saga", + "pipes-and-filters", + "rate-limiter" + ], + "categoryLabel": "Enterprise Integration", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "CQRS Pattern (Command Query Responsibility Segregation) 📋 Overview CQRS separates the write model (commands) from the read model (queries). Writes typically emit events ; reads are served from a projection optimized for queries. An example: player profile wri", + "featured": false + }, + { + "id": "pipes-and-filters", + "slug": "pipes-and-filters", + "name": "Pipes and Filters", + "category": "enterprise-integration", + "summary": "The Pipes and Filters pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes).", + "intent": "The Pipes and Filters pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes).", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Pipes and Filters", + "enterprise-integration", + "overview", + "intent", + "roles responsibilities", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Pipes", + "and", + "Filters", + "pattern", + "processes", + "data", + "through", + "series", + "independent", + "modular", + "processing", + "components", + "connected", + "flow", + "channels" + ], + "aliases": [ + "pipes and filters" + ], + "tags": [ + "enterprise-integration", + "overview", + "intent", + "roles responsibilities", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "enterprise-integration-patterns/pipes-and-filters", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/enterprise-integration-patterns/pipes-and-filters", + "demoCodePaths": [ + "enterprise-integration-patterns/pipes-and-filters/src/main/java", + "enterprise-integration-patterns/pipes-and-filters/src/main", + "enterprise-integration-patterns/pipes-and-filters/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Pipes and Filters Pattern

\n

📋 Overview

\n

The Pipes and Filters pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes).

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Process complex workflows through independent stages
  • \n
  • Enable modular, reusable components
  • \n
  • Support different processing orders
  • \n
  • Parallel and sequential processing
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
FilterIndependent processing component
PipeData flow channel between filters
SourceProduces data
SinkConsumes final result
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Source\n    class Pipe\n    class Filter {\n        +process(data)\n    }\n    class Sink\n    Source --> Pipe\n    Pipe --> Filter\n    Filter --> Pipe\n    Pipe --> Sink\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    participant Source\n    participant Pipe1\n    participant Filter\n    participant Pipe2\n    participant Sink\n    Source->>Pipe1: emit(data)\n    Pipe1->>Filter: data\n    Filter->>Pipe2: processed\n    Pipe2->>Sink: processed\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Modularity and reusability
  • \n
  • Flexible data processing
  • \n
  • Parallel processing support
  • \n
  • Easy to reconfigure
  • \n
  • Independent testing
  • \n
\n

Disadvantages ❌

\n
    \n
  • Complexity with many filters
  • \n
  • Data transformation overhead
  • \n
  • Error handling complexity
  • \n
  • Debugging difficulty
  • \n
  • Performance considerations
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Unix pipelines
  • \n
  • Data ETL processes
  • \n
  • Image processing pipelines
  • \n
  • Stream processing frameworks
  • \n
  • Log processing
  • \n
\n
\n

📚 References

\n
    \n
  • Enterprise Integration Patterns
  • \n
  • Data pipeline architecture
  • \n
\n", + "contentMarkdown": "# Pipes and Filters Pattern\n\n## 📋 Overview\n\nThe **Pipes and Filters** pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes).\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Process complex workflows through independent stages\n- Enable modular, reusable components\n- Support different processing orders\n- Parallel and sequential processing\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Filter | Independent processing component |\n| Pipe | Data flow channel between filters |\n| Source | Produces data |\n| Sink | Consumes final result |\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Source\n class Pipe\n class Filter {\n +process(data)\n }\n class Sink\n Source --> Pipe\n Pipe --> Filter\n Filter --> Pipe\n Pipe --> Sink\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n participant Source\n participant Pipe1\n participant Filter\n participant Pipe2\n participant Sink\n Source->>Pipe1: emit(data)\n Pipe1->>Filter: data\n Filter->>Pipe2: processed\n Pipe2->>Sink: processed\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Modularity and reusability\n- Flexible data processing\n- Parallel processing support\n- Easy to reconfigure\n- Independent testing\n\n### Disadvantages ❌\n- Complexity with many filters\n- Data transformation overhead\n- Error handling complexity\n- Debugging difficulty\n- Performance considerations\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Unix pipelines\n- Data ETL processes\n- Image processing pipelines\n- Stream processing frameworks\n- Log processing\n\n---\n\n## 📚 References\n\n- Enterprise Integration Patterns\n- Data pipeline architecture", + "relatedPatternIds": [ + "command", + "interpreter", + "mediator", + "memento" + ], + "categoryLabel": "Enterprise Integration", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Pipes and Filters Pattern 📋 Overview The Pipes and Filters pattern processes data through a series of independent, modular processing components (filters) connected by data flow channels (pipes). 👥 Roles & Responsibilities Role Responsibility Filter Independ", + "featured": false + }, + { + "id": "saga", + "slug": "saga", + "name": "Saga", + "category": "enterprise-integration", + "summary": "The Saga pattern manages a long running business transaction across multiple services by splitting it into steps . Each step has an optional compensation that undoes the work if a later step fails.", + "intent": "The Saga pattern manages a long running business transaction across multiple services by splitting it into steps . Each step has an optional compensation that undoes the work if a later step fails. An example: buying a legendary item may touch inventory , wallet , and granting services.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Saga", + "enterprise-integration", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "The", + "pattern", + "manages", + "long", + "running", + "business", + "transaction", + "across", + "multiple", + "services", + "splitting", + "into", + "steps", + "Each", + "step", + "has", + "optional", + "compensation", + "that", + "undoes", + "work", + "later", + "fails", + "example", + "buying", + "legendary", + "item", + "may", + "touch", + "inventory", + "wallet", + "and", + "granting", + "message flow", + "distributed transaction" + ], + "aliases": [ + "saga" + ], + "tags": [ + "enterprise-integration", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "enterprise-integration-patterns/saga", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/enterprise-integration-patterns/saga", + "demoCodePaths": [ + "enterprise-integration-patterns/saga/src/main/java", + "enterprise-integration-patterns/saga/src/main", + "enterprise-integration-patterns/saga/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Saga Pattern

\n

📋 Overview

\n

The Saga pattern manages a long-running business transaction across multiple services by splitting it into steps.\nEach step has an optional compensation that undoes the work if a later step fails.

\n

An example: buying a legendary item may touch inventory, wallet, and granting services.

\n
\n

🎯 Intent

\n
    \n
  • Replace distributed transactions (2PC) with explicit orchestration + compensations
  • \n
  • Make partial failure handling intentional and testable
  • \n
\n
\n

💡 Code Example

\n
Saga saga = Saga.builder("purchase-legendary-sword")\n    .step("reserve-inventory", reserve, release)\n    .step("charge-wallet", charge, refund)\n    .step("grant-item", grant, revoke)\n    .build();\n\nSaga.Result result = saga.run();\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Saga {\n        +builder(name) Builder\n        +run() Result\n    }\n    class Builder {\n        +step(name, action, compensation) Builder\n        +build() Saga\n    }\n    class Result {\n        +success: boolean\n        +log: List<String>\n    }\n    Builder ..> Saga : builds\n    Saga --> Result\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    participant Saga\n    participant Inventory\n    participant Wallet\n    participant Granting\n\n    Client->>Saga: run()\n    Saga->>Inventory: reserve()\n    Inventory-->>Saga: ok\n    Saga->>Wallet: charge()\n    Wallet-->>Saga: ok\n    Saga->>Granting: grant()\n    alt grant fails\n        Granting-->>Saga: error\n        Saga->>Wallet: refund() (compensate)\n        Saga->>Inventory: release() (compensate)\n        Saga-->>Client: failure\n    else grant ok\n        Granting-->>Saga: ok\n        Saga-->>Client: success\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Works well with microservices and async messaging
  • \n
  • Handles partial failures without global locks
  • \n
  • Encourages explicit recovery design
  • \n
\n

Disadvantages ❌

\n
    \n
  • Compensations are not always perfect (undo may be best-effort)
  • \n
  • Requires careful modeling of state and retries/timeouts
  • \n
\n", + "contentMarkdown": "# Saga Pattern\n\n## 📋 Overview\n\nThe **Saga** pattern manages a long-running business transaction across multiple services by splitting it into **steps**.\nEach step has an optional **compensation** that undoes the work if a later step fails.\n\nAn example: buying a legendary item may touch **inventory**, **wallet**, and **granting** services.\n\n---\n\n## 🎯 Intent\n\n- Replace distributed transactions (2PC) with **explicit orchestration + compensations**\n- Make partial failure handling intentional and testable\n\n---\n\n## 💡 Code Example\n\n```java\nSaga saga = Saga.builder(\"purchase-legendary-sword\")\n .step(\"reserve-inventory\", reserve, release)\n .step(\"charge-wallet\", charge, refund)\n .step(\"grant-item\", grant, revoke)\n .build();\n\nSaga.Result result = saga.run();\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Saga {\n +builder(name) Builder\n +run() Result\n }\n class Builder {\n +step(name, action, compensation) Builder\n +build() Saga\n }\n class Result {\n +success: boolean\n +log: List\n }\n Builder ..> Saga : builds\n Saga --> Result\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n participant Saga\n participant Inventory\n participant Wallet\n participant Granting\n\n Client->>Saga: run()\n Saga->>Inventory: reserve()\n Inventory-->>Saga: ok\n Saga->>Wallet: charge()\n Wallet-->>Saga: ok\n Saga->>Granting: grant()\n alt grant fails\n Granting-->>Saga: error\n Saga->>Wallet: refund() (compensate)\n Saga->>Inventory: release() (compensate)\n Saga-->>Client: failure\n else grant ok\n Granting-->>Saga: ok\n Saga-->>Client: success\n end\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Works well with microservices and async messaging\n- Handles partial failures without global locks\n- Encourages explicit recovery design\n\n### Disadvantages ❌\n- Compensations are not always perfect (undo may be best-effort)\n- Requires careful modeling of state and retries/timeouts", + "relatedPatternIds": [ + "transactional-outbox", + "cqrs", + "pipes-and-filters", + "rate-limiter" + ], + "categoryLabel": "Enterprise Integration", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Saga Pattern 📋 Overview The Saga pattern manages a long running business transaction across multiple services by splitting it into steps . Each step has an optional compensation that undoes the work if a later step fails. An example: buying a legendary item m", + "featured": true + }, + { + "id": "transactional-outbox", + "slug": "transactional-outbox", + "name": "Transactional Outbox", + "category": "enterprise-integration", + "summary": "The Transactional Outbox pattern ensures that when your service writes domain data, it also writes the integration event to an outbox table in the same database transaction . A separate publisher later reads the outbox and publishes events to a broker.", + "intent": "The Transactional Outbox pattern ensures that when your service writes domain data, it also writes the integration event to an outbox table in the same database transaction . A separate publisher later reads the outbox and publishes events to a broker. An example: buying coins writes an order + emits coins.purchased without losing events during crashes.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Transactional Outbox", + "enterprise-integration", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "The", + "Transactional", + "Outbox", + "pattern", + "ensures", + "that", + "when", + "your", + "service", + "writes", + "domain", + "data", + "also", + "integration", + "event", + "table", + "same", + "database", + "transaction", + "separate", + "publisher", + "later", + "reads", + "and", + "publishes", + "events", + "broker", + "example", + "buying", + "coins", + "order", + "emits", + "purchased", + "without", + "losing", + "during", + "crashes" + ], + "aliases": [ + "transactional outbox" + ], + "tags": [ + "enterprise-integration", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "enterprise-integration-patterns/transactional-outbox", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/enterprise-integration-patterns/transactional-outbox", + "demoCodePaths": [ + "enterprise-integration-patterns/transactional-outbox/src/main/java", + "enterprise-integration-patterns/transactional-outbox/src/main", + "enterprise-integration-patterns/transactional-outbox/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Transactional Outbox Pattern

\n

📋 Overview

\n

The Transactional Outbox pattern ensures that when your service writes domain data, it also writes the integration event to an outbox table in the same database transaction.\nA separate publisher later reads the outbox and publishes events to a broker.

\n

An example: buying coins writes an order + emits coins.purchased without losing events during crashes.

\n
\n

🎯 Intent

\n
    \n
  • Prevent “write succeeded but event publish failed” inconsistencies
  • \n
  • Ensure at-least-once publication with a recoverable outbox
  • \n
\n
\n

💡 Code Example

\n
var tx = db.begin();\ntx.insertOrder(playerId, coins);\ntx.addOutbox("coins.purchased", jsonPayload);\ntx.commit();\n\npublisher.publishOnce(100);\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class PurchaseService\n    class InMemoryDatabase\n    class Transaction\n    class OutboxPublisher\n    class InMemoryMessageBroker\n    PurchaseService --> InMemoryDatabase : begin tx\n    Transaction --> InMemoryDatabase : commit\n    OutboxPublisher --> InMemoryDatabase : drain outbox\n    OutboxPublisher --> InMemoryMessageBroker : publish\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    participant Service as PurchaseService\n    participant DB as Database\n    participant Outbox as OutboxTable\n    participant Pub as OutboxPublisher\n    participant Broker as MessageBroker\n\n    Client->>Service: purchaseCoins(playerId, coins)\n    Service->>DB: BEGIN\n    Service->>DB: INSERT Order\n    Service->>Outbox: INSERT OutboxMessage\n    Service->>DB: COMMIT\n\n    Pub->>Outbox: poll batch\n    Outbox-->>Pub: messages\n    Pub->>Broker: publish(topic, payload)\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Strong consistency between domain write and event record
  • \n
  • Simple recovery: publish from outbox after restart
  • \n
\n

Disadvantages ❌

\n
    \n
  • Requires polling/streaming outbox and operational tooling
  • \n
  • Needs idempotent publishing/consumers (at-least-once)
  • \n
\n", + "contentMarkdown": "# Transactional Outbox Pattern\n\n## 📋 Overview\n\nThe **Transactional Outbox** pattern ensures that when your service writes domain data, it also writes the integration event to an **outbox table** in the **same database transaction**.\nA separate publisher later reads the outbox and publishes events to a broker.\n\nAn example: buying coins writes an order + emits `coins.purchased` without losing events during crashes.\n\n---\n\n## 🎯 Intent\n\n- Prevent “write succeeded but event publish failed” inconsistencies\n- Ensure at-least-once publication with a recoverable outbox\n\n---\n\n## 💡 Code Example\n\n```java\nvar tx = db.begin();\ntx.insertOrder(playerId, coins);\ntx.addOutbox(\"coins.purchased\", jsonPayload);\ntx.commit();\n\npublisher.publishOnce(100);\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class PurchaseService\n class InMemoryDatabase\n class Transaction\n class OutboxPublisher\n class InMemoryMessageBroker\n PurchaseService --> InMemoryDatabase : begin tx\n Transaction --> InMemoryDatabase : commit\n OutboxPublisher --> InMemoryDatabase : drain outbox\n OutboxPublisher --> InMemoryMessageBroker : publish\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n participant Service as PurchaseService\n participant DB as Database\n participant Outbox as OutboxTable\n participant Pub as OutboxPublisher\n participant Broker as MessageBroker\n\n Client->>Service: purchaseCoins(playerId, coins)\n Service->>DB: BEGIN\n Service->>DB: INSERT Order\n Service->>Outbox: INSERT OutboxMessage\n Service->>DB: COMMIT\n\n Pub->>Outbox: poll batch\n Outbox-->>Pub: messages\n Pub->>Broker: publish(topic, payload)\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Strong consistency between domain write and event record\n- Simple recovery: publish from outbox after restart\n\n### Disadvantages ❌\n- Requires polling/streaming outbox and operational tooling\n- Needs idempotent publishing/consumers (at-least-once)", + "relatedPatternIds": [ + "saga", + "cqrs", + "pipes-and-filters", + "observer" + ], + "categoryLabel": "Enterprise Integration", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Transactional Outbox Pattern 📋 Overview The Transactional Outbox pattern ensures that when your service writes domain data, it also writes the integration event to an outbox table in the same database transaction . A separate publisher later reads the outbox ", + "featured": false + }, + { + "id": "bulkhead", + "slug": "bulkhead", + "name": "Bulkhead", + "category": "reliability", + "summary": "The Bulkhead pattern limits concurrency to isolate failures and resource exhaustion. If one dependency becomes slow, it cannot consume all threads/connections.", + "intent": "The Bulkhead pattern limits concurrency to isolate failures and resource exhaustion. If one dependency becomes slow, it cannot consume all threads/connections. An example: isolate inventory calls so a slow inventory DB does not take down matchmaking.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Bulkhead", + "reliability", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "The", + "pattern", + "limits", + "concurrency", + "isolate", + "failures", + "and", + "resource", + "exhaustion", + "one", + "dependency", + "becomes", + "slow", + "cannot", + "consume", + "all", + "threads", + "connections", + "example", + "inventory", + "calls", + "does", + "not", + "take", + "down", + "matchmaking" + ], + "aliases": [ + "bulkhead" + ], + "tags": [ + "reliability", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "reliability-patterns/bulkhead", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/bulkhead", + "demoCodePaths": [ + "reliability-patterns/bulkhead/src/main/java", + "reliability-patterns/bulkhead/src/main", + "reliability-patterns/bulkhead/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Bulkhead Pattern

\n

📋 Overview

\n

The Bulkhead pattern limits concurrency to isolate failures and resource exhaustion. If one dependency becomes slow, it cannot consume all threads/connections.

\n

An example: isolate inventory calls so a slow inventory DB does not take down matchmaking.

\n
\n

💡 Code Example

\n
var bulkhead = Bulkhead.builder("inventory-service")\n    .maxConcurrent(5)\n    .maxWait(Duration.ofMillis(20))\n    .build();\n\nbulkhead.execute(() -> loadInventory(playerId));\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Bulkhead {\n        +builder(name) Builder\n        +execute(op) T\n    }\n    class Builder {\n        +maxConcurrent(n) Builder\n        +maxWait(d) Builder\n        +build() Bulkhead\n    }\n    class BulkheadFullException\n    Builder ..> Bulkhead : builds\n    Bulkhead ..> BulkheadFullException : throws\n
\n

\"Bulkhead

\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Prevents one dependency from exhausting capacity
  • \n
  • Simple mental model (permits)
  • \n
\n

Disadvantages ❌

\n
    \n
  • Needs sizing and separate pools per dependency
  • \n
\n", + "contentMarkdown": "# Bulkhead Pattern\n\n## 📋 Overview\n\nThe **Bulkhead** pattern limits concurrency to isolate failures and resource exhaustion. If one dependency becomes slow, it cannot consume all threads/connections.\n\nAn example: isolate **inventory** calls so a slow inventory DB does not take down matchmaking.\n\n---\n\n## 💡 Code Example\n\n```java\nvar bulkhead = Bulkhead.builder(\"inventory-service\")\n .maxConcurrent(5)\n .maxWait(Duration.ofMillis(20))\n .build();\n\nbulkhead.execute(() -> loadInventory(playerId));\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Bulkhead {\n +builder(name) Builder\n +execute(op) T\n }\n class Builder {\n +maxConcurrent(n) Builder\n +maxWait(d) Builder\n +build() Bulkhead\n }\n class BulkheadFullException\n Builder ..> Bulkhead : builds\n Bulkhead ..> BulkheadFullException : throws\n```\n\n![Bulkhead class diagram](bulkhead-class-diagram.png)\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n\n- Prevents one dependency from exhausting capacity\n- Simple mental model (permits)\n\n### Disadvantages ❌\n\n- Needs sizing and separate pools per dependency", + "relatedPatternIds": [ + "rate-limiter", + "circuit-breaker", + "retry-backoff", + "hedge-requests" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Bulkhead Pattern 📋 Overview The Bulkhead pattern limits concurrency to isolate failures and resource exhaustion. If one dependency becomes slow, it cannot consume all threads/connections. An example: isolate inventory calls so a slow inventory DB does not tak", + "featured": false + }, + { + "id": "circuit-breaker", + "slug": "circuit-breaker", + "name": "Circuit Breaker", + "category": "reliability", + "summary": "The Circuit Breaker pattern prevents your system from repeatedly calling a failing dependency. When failures cross a threshold, the breaker opens and short circuits calls for a cool down period. After that, it allows limited trial calls (half open) to check whether the dependency recovered.", + "intent": "The Circuit Breaker pattern prevents your system from repeatedly calling a failing dependency. When failures cross a threshold, the breaker opens and short circuits calls for a cool down period. After that, it allows limited trial calls (half open) to check whether the dependency recovered.", + "applicability": [ + "For in-process calls where failures are not correlated", + "When you cannot tolerate short-circuiting (must always attempt)", + "If you cannot operationally monitor and tune it" + ], + "tradeOffs": [], + "alternatives": [ + "For in-process calls where failures are not correlated", + "When you cannot tolerate short-circuiting (must always attempt)", + "If you cannot operationally monitor and tune it" + ], + "keywords": [ + "Circuit Breaker", + "reliability", + "overview", + "intent", + "roles responsibilities", + "code example java 21 virtual threads", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "best practices", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example (Java 21 + Virtual Threads)", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "📝 Best Practices", + "The", + "Circuit", + "Breaker", + "pattern", + "prevents", + "your", + "system", + "from", + "repeatedly", + "calling", + "failing", + "dependency", + "When", + "failures", + "cross", + "threshold", + "opens", + "and", + "short", + "circuits", + "calls", + "for", + "cool", + "down", + "period", + "After", + "that", + "allows", + "limited", + "trial", + "half", + "open", + "check", + "whether", + "recovered", + "resilience", + "retry remote calls" + ], + "aliases": [ + "circuit breaker" + ], + "tags": [ + "reliability", + "overview", + "intent", + "roles responsibilities", + "code example java 21 virtual threads", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "when not to use", + "best practices" + ], + "githubPath": "reliability-patterns/circuit-breaker", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/circuit-breaker", + "demoCodePaths": [ + "reliability-patterns/circuit-breaker/src/main/java", + "reliability-patterns/circuit-breaker/src/main", + "reliability-patterns/circuit-breaker/src" + ], + "hasTests": true, + "readingTimeMinutes": 2, + "contentHtml": "

\n

Circuit Breaker Pattern

\n

📋 Overview

\n

The Circuit Breaker pattern prevents your system from repeatedly calling a failing dependency.\nWhen failures cross a threshold, the breaker opens and short-circuits calls for a cool-down period.\nAfter that, it allows limited trial calls (half-open) to check whether the dependency recovered.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Stop cascading failures when a downstream service is unhealthy
  • \n
  • Reduce load on dependencies during incidents
  • \n
  • Fail fast (and consistently) instead of hanging or retrying endlessly
  • \n
\n

Use When:

\n
    \n
  • You call remote services, databases, or third-party APIs
  • \n
  • Failures tend to be correlated (outages, overload, rate limits)
  • \n
  • You want controlled recovery behavior after an outage
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ClientCalls execute(...) to run a protected operation
CircuitBreakerTracks health and blocks/permits calls based on state
DownstreamThe dependency that may fail (HTTP, DB, etc.)
\n
\n

💡 Code Example (Java 21 + Virtual Threads)

\n
var breaker = CircuitBreaker.builder("external-api")\n    .failureThreshold(3)\n    .openDuration(Duration.ofSeconds(2))\n    .halfOpenMaxCalls(1)\n    .halfOpenSuccessThreshold(1)\n    .build();\n\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n  executor.submit(() -> breaker.executeUnchecked(() -> {\n    return callRemoteApi(); // may throw\n  }));\n}\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class CircuitBreaker {\n        +builder(name) Builder\n        +execute(op) T\n        +executeUnchecked(op) T\n        +state() State\n    }\n    class CircuitBreakerOpenException\n    class Builder {\n        +failureThreshold(n) Builder\n        +openDuration(d) Builder\n        +halfOpenMaxCalls(n) Builder\n        +halfOpenSuccessThreshold(n) Builder\n        +build() CircuitBreaker\n    }\n    class State {\n        <<enumeration>>\n        CLOSED\n        OPEN\n        HALF_OPEN\n    }\n    Builder ..> CircuitBreaker : builds\n    CircuitBreaker --> State\n    CircuitBreaker ..> CircuitBreakerOpenException : throws\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    participant CB as CircuitBreaker\n    participant DS as Downstream\n\n    Client->>CB: execute(operation)\n    alt CLOSED\n        CB->>DS: call\n        alt success\n            DS-->>CB: ok\n            CB-->>Client: result\n        else failure\n            DS-->>CB: exception\n            CB->>CB: increment failures\n            CB-->>Client: exception\n        end\n    else OPEN\n        CB-->>Client: CircuitBreakerOpenException\n    else HALF_OPEN\n        CB->>DS: trial call\n        alt success threshold met\n            CB->>CB: transition to CLOSED\n        else failure\n            CB->>CB: transition to OPEN\n        end\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Prevents cascading failures and reduces blast radius
  • \n
  • Gives dependencies time to recover (cool-down)
  • \n
  • Improves latency by failing fast when unhealthy
  • \n
  • Makes recovery behavior explicit and testable
  • \n
\n

Disadvantages ❌

\n
    \n
  • Adds state and tuning parameters (thresholds, timers)
  • \n
  • Wrong settings can cause flapping (open/close too frequently)
  • \n
  • Needs good observability to diagnose and tune
  • \n
\n
\n

🚫 When NOT to Use

\n
    \n
  • For in-process calls where failures are not correlated
  • \n
  • When you cannot tolerate short-circuiting (must always attempt)
  • \n
  • If you cannot operationally monitor and tune it
  • \n
\n
\n

📝 Best Practices

\n
    \n
  1. Start with simple thresholds, then tune with real data
  2. \n
  3. Combine with timeouts (a breaker without timeouts is incomplete)
  4. \n
  5. Emit metrics (state, opens, rejections, failures, successes)
  6. \n
  7. Prefer bounded half-open trials to avoid thundering herds
  8. \n
  9. Keep the protected operation small and side-effect aware
  10. \n
\n", + "contentMarkdown": "#\n\n# Circuit Breaker Pattern\n\n## 📋 Overview\n\nThe **Circuit Breaker** pattern prevents your system from repeatedly calling a failing dependency.\nWhen failures cross a threshold, the breaker **opens** and short-circuits calls for a cool-down period.\nAfter that, it allows limited **trial calls** (half-open) to check whether the dependency recovered.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n\n- Stop cascading failures when a downstream service is unhealthy\n- Reduce load on dependencies during incidents\n- Fail fast (and consistently) instead of hanging or retrying endlessly\n\n**Use When:**\n\n- You call remote services, databases, or third-party APIs\n- Failures tend to be correlated (outages, overload, rate limits)\n- You want controlled recovery behavior after an outage\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|----------------|\n| Client | Calls `execute(...)` to run a protected operation |\n| CircuitBreaker | Tracks health and blocks/permits calls based on state |\n| Downstream | The dependency that may fail (HTTP, DB, etc.) |\n\n---\n\n## 💡 Code Example (Java 21 + Virtual Threads)\n\n```java\nvar breaker = CircuitBreaker.builder(\"external-api\")\n .failureThreshold(3)\n .openDuration(Duration.ofSeconds(2))\n .halfOpenMaxCalls(1)\n .halfOpenSuccessThreshold(1)\n .build();\n\ntry (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n executor.submit(() -> breaker.executeUnchecked(() -> {\n return callRemoteApi(); // may throw\n }));\n}\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class CircuitBreaker {\n +builder(name) Builder\n +execute(op) T\n +executeUnchecked(op) T\n +state() State\n }\n class CircuitBreakerOpenException\n class Builder {\n +failureThreshold(n) Builder\n +openDuration(d) Builder\n +halfOpenMaxCalls(n) Builder\n +halfOpenSuccessThreshold(n) Builder\n +build() CircuitBreaker\n }\n class State {\n <>\n CLOSED\n OPEN\n HALF_OPEN\n }\n Builder ..> CircuitBreaker : builds\n CircuitBreaker --> State\n CircuitBreaker ..> CircuitBreakerOpenException : throws\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n participant CB as CircuitBreaker\n participant DS as Downstream\n\n Client->>CB: execute(operation)\n alt CLOSED\n CB->>DS: call\n alt success\n DS-->>CB: ok\n CB-->>Client: result\n else failure\n DS-->>CB: exception\n CB->>CB: increment failures\n CB-->>Client: exception\n end\n else OPEN\n CB-->>Client: CircuitBreakerOpenException\n else HALF_OPEN\n CB->>DS: trial call\n alt success threshold met\n CB->>CB: transition to CLOSED\n else failure\n CB->>CB: transition to OPEN\n end\n end\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n\n- Prevents cascading failures and reduces blast radius\n- Gives dependencies time to recover (cool-down)\n- Improves latency by failing fast when unhealthy\n- Makes recovery behavior explicit and testable\n\n### Disadvantages ❌\n\n- Adds state and tuning parameters (thresholds, timers)\n- Wrong settings can cause flapping (open/close too frequently)\n- Needs good observability to diagnose and tune\n\n---\n\n## 🚫 When NOT to Use\n\n- For in-process calls where failures are not correlated\n- When you cannot tolerate short-circuiting (must always attempt)\n- If you cannot operationally monitor and tune it\n\n---\n\n## 📝 Best Practices\n\n1. Start with simple thresholds, then tune with real data\n2. Combine with timeouts (a breaker without timeouts is incomplete)\n3. Emit metrics (state, opens, rejections, failures, successes)\n4. Prefer bounded half-open trials to avoid thundering herds\n5. Keep the protected operation small and side-effect aware", + "relatedPatternIds": [ + "rate-limiter", + "bulkhead", + "builder", + "abstract-factory" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Code Example (Java 21 + Virtual Threads)", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🚫 When NOT to Use", + "📝 Best Practices" + ], + "excerpt": "Circuit Breaker Pattern 📋 Overview The Circuit Breaker pattern prevents your system from repeatedly calling a failing dependency. When failures cross a threshold, the breaker opens and short circuits calls for a cool down period. After that, it allows limited", + "featured": true + }, + { + "id": "double-checked-locking", + "slug": "double-checked-locking", + "name": "Double-Checked Locking", + "category": "reliability", + "summary": "The Double Checked Locking pattern is a thread safe lazy initialization technique that minimizes synchronization overhead.", + "intent": "The Double Checked Locking pattern is a thread safe lazy initialization technique that minimizes synchronization overhead.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Double-Checked Locking", + "reliability", + "double checked locking", + "DCL", + "overview", + "intent", + "implementation", + "considerations", + "class diagram", + "sequence diagram", + "references", + "📋 Overview", + "🎯 Intent", + "💡 Implementation", + "⚠️ Considerations", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "📚 References", + "The", + "Double", + "Checked", + "Locking", + "pattern", + "thread", + "safe", + "lazy", + "initialization", + "technique", + "that", + "minimizes", + "synchronization", + "overhead" + ], + "aliases": [ + "double checked locking", + "Double-Checked Locking", + "DCL" + ], + "tags": [ + "reliability", + "overview", + "intent", + "implementation", + "considerations", + "class diagram", + "sequence diagram", + "references" + ], + "githubPath": "reliability-patterns/double-checked-locking", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/double-checked-locking", + "demoCodePaths": [ + "reliability-patterns/double-checked-locking/src/main/java", + "reliability-patterns/double-checked-locking/src/main", + "reliability-patterns/double-checked-locking/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Double-Checked Locking Pattern

\n

📋 Overview

\n

The Double-Checked Locking pattern is a thread-safe lazy initialization technique that minimizes synchronization overhead.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Thread-safe lazy initialization
  • \n
  • Minimize synchronization overhead
  • \n
  • Defer object creation until needed
  • \n
  • Efficient repeated access
  • \n
\n
\n

💡 Implementation

\n
public class DoubleCheckedLocking {\n    private volatile static Instance instance;\n    \n    public static Instance getInstance() {\n        if (instance == null) {\n            synchronized(DoubleCheckedLocking.class) {\n                if (instance == null) {\n                    instance = new Instance();\n                }\n            }\n        }\n        return instance;\n    }\n}\n
\n
\n

⚠️ Considerations

\n
    \n
  • Requires volatile keyword
  • \n
  • Subtle synchronization issues
  • \n
  • Java Memory Model dependent
  • \n
  • Bill Pugh Singleton often better
  • \n
  • Enum Singleton recommended
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Singleton {\n        -static instance: Singleton\n        +getInstance(): Singleton\n    }\n    Client --> Singleton\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Singleton: getInstance()\n    alt instance == null\n        Client->>Singleton: synchronize\n        Singleton->>Singleton: create instance\n    end\n    Singleton-->>Client: instance\n
\n
\n

📚 References

\n
    \n
  • Double-Checked Locking pattern
  • \n
  • Effective Java Chapter on Lazy Initialization
  • \n
\n", + "contentMarkdown": "# Double-Checked Locking Pattern\n\n## 📋 Overview\n\nThe **Double-Checked Locking** pattern is a thread-safe lazy initialization technique that minimizes synchronization overhead.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Thread-safe lazy initialization\n- Minimize synchronization overhead\n- Defer object creation until needed\n- Efficient repeated access\n\n---\n\n## 💡 Implementation\n\n```java\npublic class DoubleCheckedLocking {\n private volatile static Instance instance;\n \n public static Instance getInstance() {\n if (instance == null) {\n synchronized(DoubleCheckedLocking.class) {\n if (instance == null) {\n instance = new Instance();\n }\n }\n }\n return instance;\n }\n}\n```\n\n---\n\n## ⚠️ Considerations\n\n- Requires volatile keyword\n- Subtle synchronization issues\n- Java Memory Model dependent\n- Bill Pugh Singleton often better\n- Enum Singleton recommended\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Singleton {\n -static instance: Singleton\n +getInstance(): Singleton\n }\n Client --> Singleton\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Singleton: getInstance()\n alt instance == null\n Client->>Singleton: synchronize\n Singleton->>Singleton: create instance\n end\n Singleton-->>Client: instance\n```\n\n---\n\n## 📚 References\n\n- Double-Checked Locking pattern\n- Effective Java Chapter on Lazy Initialization", + "relatedPatternIds": [ + "nullobject", + "circuit-breaker", + "interpreter", + "mediator" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Implementation", + "⚠️ Considerations", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "📚 References" + ], + "excerpt": "Double Checked Locking Pattern 📋 Overview The Double Checked Locking pattern is a thread safe lazy initialization technique that minimizes synchronization overhead. 💡 Implementation ⚠️ Considerations Requires volatile keyword Subtle synchronization issues Ja", + "featured": false + }, + { + "id": "hedge-requests", + "slug": "hedge-requests", + "name": "Hedge Requests", + "category": "reliability", + "summary": "Hedging issues a duplicate request when the primary is slow, returning the first successful response. This reduces tail latency but increases load.", + "intent": "Hedging issues a duplicate request when the primary is slow, returning the first successful response. This reduces tail latency but increases load. An example: hedge read only profile fetches across replicas. Only safe for idempotent reads (or when combined with idempotency keys).", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Hedge Requests", + "reliability", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "Hedging", + "issues", + "duplicate", + "request", + "when", + "the", + "primary", + "slow", + "returning", + "first", + "successful", + "response", + "This", + "reduces", + "tail", + "latency", + "but", + "increases", + "load", + "example", + "hedge", + "read", + "only", + "profile", + "fetches", + "across", + "replicas", + "safe", + "for", + "idempotent", + "reads", + "combined", + "with", + "idempotency", + "keys" + ], + "aliases": [ + "hedge requests" + ], + "tags": [ + "reliability", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "reliability-patterns/hedge-requests", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/hedge-requests", + "demoCodePaths": [ + "reliability-patterns/hedge-requests/src/main/java", + "reliability-patterns/hedge-requests/src/main", + "reliability-patterns/hedge-requests/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Hedge Requests Pattern

\n

📋 Overview

\n

Hedging issues a duplicate request when the primary is slow, returning the first successful response. This reduces tail latency but increases load.

\n

An example: hedge read-only profile fetches across replicas.

\n
\n

Only safe for idempotent reads (or when combined with idempotency keys).

\n
\n
\n

💡 Code Example

\n
try (var hedger = HedgeRequests.builder("player-profile")\n    .hedgeDelay(Duration.ofMillis(20))\n    .maxHedges(1)\n    .build()) {\n  hedger.executeIdempotent(() -> loadProfile(playerId));\n}\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class HedgeRequests {\n        +builder(name) Builder\n        +executeIdempotent(op) T\n        +close()\n    }\n    class Builder {\n        +hedgeDelay(d) Builder\n        +maxHedges(n) Builder\n        +build() HedgeRequests\n    }\n    Builder ..> HedgeRequests : builds\n
\n

\"HedgeRequests

\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Reduces tail latency
  • \n
  • Works well for read replicas and caches
  • \n
\n

Disadvantages ❌

\n
    \n
  • Increases load (extra calls)
  • \n
  • Dangerous for non-idempotent operations
  • \n
\n", + "contentMarkdown": "# Hedge Requests Pattern\n\n## 📋 Overview\n\n**Hedging** issues a duplicate request when the primary is slow, returning the first successful response. This reduces tail latency but increases load.\n\nAn example: hedge **read-only profile fetches** across replicas.\n\n> Only safe for idempotent reads (or when combined with idempotency keys).\n\n---\n\n## 💡 Code Example\n\n```java\ntry (var hedger = HedgeRequests.builder(\"player-profile\")\n .hedgeDelay(Duration.ofMillis(20))\n .maxHedges(1)\n .build()) {\n hedger.executeIdempotent(() -> loadProfile(playerId));\n}\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class HedgeRequests {\n +builder(name) Builder\n +executeIdempotent(op) T\n +close()\n }\n class Builder {\n +hedgeDelay(d) Builder\n +maxHedges(n) Builder\n +build() HedgeRequests\n }\n Builder ..> HedgeRequests : builds\n```\n\n![HedgeRequests class diagram](hedge-requests-class-diagram.png)\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Reduces tail latency\n- Works well for read replicas and caches\n\n### Disadvantages ❌\n- Increases load (extra calls)\n- Dangerous for non-idempotent operations", + "relatedPatternIds": [ + "bulkhead", + "rate-limiter", + "retry-backoff", + "cqrs" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Hedge Requests Pattern 📋 Overview Hedging issues a duplicate request when the primary is slow, returning the first successful response. This reduces tail latency but increases load. An example: hedge read only profile fetches across replicas. Only safe for id", + "featured": false + }, + { + "id": "idempotency-keys", + "slug": "idempotency-keys", + "name": "Idempotency Keys", + "category": "reliability", + "summary": "Idempotency keys ensure that repeated requests with the same key produce the same effect/result, even if the client retries due to timeouts.", + "intent": "Idempotency keys ensure that repeated requests with the same key produce the same effect/result, even if the client retries due to timeouts. An example: prevent double charging when purchasing in game currency if the client retries.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Idempotency Keys", + "reliability", + "overview", + "code example", + "class diagram", + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "Idempotency", + "keys", + "ensure", + "that", + "repeated", + "requests", + "with", + "the", + "same", + "key", + "produce", + "effect", + "result", + "even", + "client", + "retries", + "due", + "timeouts", + "example", + "prevent", + "double", + "charging", + "when", + "purchasing", + "game", + "currency" + ], + "aliases": [ + "idempotency keys" + ], + "tags": [ + "reliability", + "overview", + "code example", + "class diagram" + ], + "githubPath": "reliability-patterns/idempotency-keys", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/idempotency-keys", + "demoCodePaths": [ + "reliability-patterns/idempotency-keys/src/main/java", + "reliability-patterns/idempotency-keys/src/main", + "reliability-patterns/idempotency-keys/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Idempotency Keys Pattern

\n

📋 Overview

\n

Idempotency keys ensure that repeated requests with the same key produce the same effect/result, even if the client retries due to timeouts.

\n

An example: prevent double-charging when purchasing in-game currency if the client retries.

\n
\n

💡 Code Example

\n
var store = IdempotencyKeys.builder("purchase")\n    .ttl(Duration.ofMinutes(5))\n    .build();\n\nString result = store.execute("purchase:player-42:order-1001", () -> chargeAndGrantCoins());\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class IdempotencyKeys {\n        +builder(name) Builder\n        +execute(key, op) T\n    }\n    class Builder {\n        +ttl(d) Builder\n        +removeOnFailure(b) Builder\n        +build() IdempotencyKeys\n    }\n    Builder ..> IdempotencyKeys : builds\n
\n

\"IdempotencyKeys

\n", + "contentMarkdown": "# Idempotency Keys Pattern\n\n## 📋 Overview\n\n**Idempotency keys** ensure that repeated requests with the same key produce the same effect/result, even if the client retries due to timeouts.\n\nAn example: prevent double-charging when purchasing in-game currency if the client retries.\n\n---\n\n## 💡 Code Example\n\n```java\nvar store = IdempotencyKeys.builder(\"purchase\")\n .ttl(Duration.ofMinutes(5))\n .build();\n\nString result = store.execute(\"purchase:player-42:order-1001\", () -> chargeAndGrantCoins());\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class IdempotencyKeys {\n +builder(name) Builder\n +execute(key, op) T\n }\n class Builder {\n +ttl(d) Builder\n +removeOnFailure(b) Builder\n +build() IdempotencyKeys\n }\n Builder ..> IdempotencyKeys : builds\n```\n\n![IdempotencyKeys class diagram](idempotency-keys-class-diagram.png)", + "relatedPatternIds": [ + "hedge-requests", + "retry-backoff", + "timeout-deadline-propagation", + "rate-limiter" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram" + ], + "excerpt": "Idempotency Keys Pattern 📋 Overview Idempotency keys ensure that repeated requests with the same key produce the same effect/result, even if the client retries due to timeouts. An example: prevent double charging when purchasing in game currency if the client", + "featured": false + }, + { + "id": "nullobject", + "slug": "nullobject", + "name": "Null Object", + "category": "reliability", + "summary": "The Null Object pattern provides an object as a surrogate for null references, avoiding null checks throughout the code.", + "intent": "The Null Object pattern provides an object as a surrogate for null references, avoiding null checks throughout the code.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Null Object", + "reliability", + "nullobject", + "null-object", + "overview", + "intent", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Null", + "Object", + "pattern", + "provides", + "surrogate", + "for", + "avoiding", + "checks", + "throughout", + "code" + ], + "aliases": [ + "nullobject", + "Null Object", + "null-object" + ], + "tags": [ + "reliability", + "overview", + "intent", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "reliability-patterns/nullobject", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/nullobject", + "demoCodePaths": [ + "reliability-patterns/nullobject/src/main/java", + "reliability-patterns/nullobject/src/main", + "reliability-patterns/nullobject/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Null Object Pattern

\n

📋 Overview

\n

The Null Object pattern provides an object as a surrogate for null references, avoiding null checks throughout the code.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Eliminate null reference checks
  • \n
  • Provide default behavior for null case
  • \n
  • Improve code clarity
  • \n
  • Reduce NullPointerException risks
  • \n
\n
\n

💡 Implementation

\n

Instead of:

\n
if (logger != null) {\n    logger.log("message");\n}\n
\n

Use:

\n
logger.log("message");  // Works with NullLogger\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class AbstractObject {\n        <<interface>>\n        +operation()\n    }\n    class RealObject\n    class NullObject\n    Client --> AbstractObject\n    AbstractObject <|-- RealObject\n    AbstractObject <|-- NullObject\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>AbstractObject: operation()\n    AbstractObject-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Eliminates null checks
  • \n
  • Default behavior encapsulated
  • \n
  • Cleaner code
  • \n
  • Safer code
  • \n
  • Visitor pattern support
  • \n
\n

Disadvantages ❌

\n
    \n
  • Silent failures possible
  • \n
  • Harder to detect issues
  • \n
  • Performance overhead
  • \n
  • Over-abstraction risk
  • \n
  • Debugging complexity
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Logging no-op implementations
  • \n
  • Optional services
  • \n
  • Collection empty implementations
  • \n
  • Null object patterns in frameworks
  • \n
\n
\n

📚 References

\n
    \n
  • Null Object pattern
  • \n
  • Optional design
  • \n
\n", + "contentMarkdown": "# Null Object Pattern\n\n## 📋 Overview\n\nThe **Null Object** pattern provides an object as a surrogate for null references, avoiding null checks throughout the code.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Eliminate null reference checks\n- Provide default behavior for null case\n- Improve code clarity\n- Reduce NullPointerException risks\n\n---\n\n## 💡 Implementation\n\nInstead of:\n```java\nif (logger != null) {\n logger.log(\"message\");\n}\n```\n\nUse:\n```java\nlogger.log(\"message\"); // Works with NullLogger\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class AbstractObject {\n <>\n +operation()\n }\n class RealObject\n class NullObject\n Client --> AbstractObject\n AbstractObject <|-- RealObject\n AbstractObject <|-- NullObject\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>AbstractObject: operation()\n AbstractObject-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Eliminates null checks\n- Default behavior encapsulated\n- Cleaner code\n- Safer code\n- Visitor pattern support\n\n### Disadvantages ❌\n- Silent failures possible\n- Harder to detect issues\n- Performance overhead\n- Over-abstraction risk\n- Debugging complexity\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Logging no-op implementations\n- Optional services\n- Collection empty implementations\n- Null object patterns in frameworks\n\n---\n\n## 📚 References\n\n- Null Object pattern\n- Optional design", + "relatedPatternIds": [ + "interpreter", + "iterator", + "filter", + "servant" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Null Object Pattern 📋 Overview The Null Object pattern provides an object as a surrogate for null references, avoiding null checks throughout the code. 💡 Implementation Instead of: Use: 📊 Class Diagram 🔄 Sequence Diagram ⚖️ Trade offs Advantages ✅ Eliminat", + "featured": false + }, + { + "id": "rate-limiter", + "slug": "rate-limiter", + "name": "Rate Limiter", + "category": "reliability", + "summary": "The Rate Limiter pattern controls how frequently an operation is allowed to run. It protects shared resources from spikes and prevents a single client from monopolizing capacity.", + "intent": "The Rate Limiter pattern controls how frequently an operation is allowed to run. It protects shared resources from spikes and prevents a single client from monopolizing capacity. An example: limit leaderboard refresh or matchmaking search calls per player to reduce load.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Rate Limiter", + "reliability", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "The", + "Rate", + "Limiter", + "pattern", + "controls", + "how", + "frequently", + "operation", + "allowed", + "run", + "protects", + "shared", + "resources", + "from", + "spikes", + "and", + "prevents", + "single", + "client", + "monopolizing", + "capacity", + "example", + "limit", + "leaderboard", + "refresh", + "matchmaking", + "search", + "calls", + "per", + "player", + "reduce", + "load" + ], + "aliases": [ + "rate limiter" + ], + "tags": [ + "reliability", + "overview", + "intent", + "code example", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "reliability-patterns/rate-limiter", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/rate-limiter", + "demoCodePaths": [ + "reliability-patterns/rate-limiter/src/main/java", + "reliability-patterns/rate-limiter/src/main", + "reliability-patterns/rate-limiter/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Rate Limiter Pattern

\n

📋 Overview

\n

The Rate Limiter pattern controls how frequently an operation is allowed to run. It protects shared resources from spikes and prevents a single client from monopolizing capacity.

\n

An example: limit leaderboard refresh or matchmaking search calls per player to reduce load.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Prevent overload caused by bursts (client retries, bot traffic, thundering herds)
  • \n
  • Enforce fairness per key (player, session, API key, tenant)
  • \n
  • Provide predictable capacity planning and cost control
  • \n
\n
\n

💡 Code Example

\n
var limiter = TokenBucketRateLimiter.builder("leaderboard-refresh")\n    .capacity(5)\n    .refill(5, Duration.ofSeconds(1))\n    .build();\n\nlimiter.execute(() -> refreshLeaderboard(), Duration.ofMillis(10));\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class TokenBucketRateLimiter {\n        +builder(name) Builder\n        +tryAcquire() boolean\n        +tryAcquire(timeout) boolean\n        +execute(op, timeout) T\n    }\n    class Builder {\n        +capacity(n) Builder\n        +refill(tokens, period) Builder\n        +build() TokenBucketRateLimiter\n    }\n    class RateLimitedException\n    Builder ..> TokenBucketRateLimiter : builds\n    TokenBucketRateLimiter ..> RateLimitedException : throws\n
\n

\"TokenBucketRateLimiter

\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    participant RL as RateLimiter\n\n    Client->>RL: tryAcquire()\n    alt tokens available\n        RL-->>Client: true\n        Client->>RL: execute(op)\n        RL-->>Client: result\n    else empty\n        RL-->>Client: false\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Protects systems from bursts and abuse
  • \n
  • Improves fairness across clients
  • \n
  • Reduces tail latency under load
  • \n
\n

Disadvantages ❌

\n
    \n
  • Requires tuning (capacity, refill rate)
  • \n
  • Needs a strategy per-key and storage (in-memory vs distributed)
  • \n
\n", + "contentMarkdown": "# Rate Limiter Pattern\n\n## 📋 Overview\n\nThe **Rate Limiter** pattern controls how frequently an operation is allowed to run. It protects shared resources from spikes and prevents a single client from monopolizing capacity.\n\nAn example: limit **leaderboard refresh** or **matchmaking search** calls per player to reduce load.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Prevent overload caused by bursts (client retries, bot traffic, thundering herds)\n- Enforce fairness per key (player, session, API key, tenant)\n- Provide predictable capacity planning and cost control\n\n---\n\n## 💡 Code Example\n\n```java\nvar limiter = TokenBucketRateLimiter.builder(\"leaderboard-refresh\")\n .capacity(5)\n .refill(5, Duration.ofSeconds(1))\n .build();\n\nlimiter.execute(() -> refreshLeaderboard(), Duration.ofMillis(10));\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class TokenBucketRateLimiter {\n +builder(name) Builder\n +tryAcquire() boolean\n +tryAcquire(timeout) boolean\n +execute(op, timeout) T\n }\n class Builder {\n +capacity(n) Builder\n +refill(tokens, period) Builder\n +build() TokenBucketRateLimiter\n }\n class RateLimitedException\n Builder ..> TokenBucketRateLimiter : builds\n TokenBucketRateLimiter ..> RateLimitedException : throws\n```\n\n![TokenBucketRateLimiter class diagram](rate-limiter-class-diagram.png)\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n participant RL as RateLimiter\n\n Client->>RL: tryAcquire()\n alt tokens available\n RL-->>Client: true\n Client->>RL: execute(op)\n RL-->>Client: result\n else empty\n RL-->>Client: false\n end\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Protects systems from bursts and abuse\n- Improves fairness across clients\n- Reduces tail latency under load\n\n### Disadvantages ❌\n- Requires tuning (capacity, refill rate)\n- Needs a strategy per-key and storage (in-memory vs distributed)", + "relatedPatternIds": [ + "circuit-breaker", + "bulkhead", + "nullobject", + "saga" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "💡 Code Example", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Rate Limiter Pattern 📋 Overview The Rate Limiter pattern controls how frequently an operation is allowed to run. It protects shared resources from spikes and prevents a single client from monopolizing capacity. An example: limit leaderboard refresh or matchma", + "featured": false + }, + { + "id": "retry-backoff", + "slug": "retry-backoff", + "name": "Retry with Backoff", + "category": "reliability", + "summary": "Retry with backoff retries transient failures while avoiding immediate, synchronized retries that amplify outages.", + "intent": "Retry with backoff retries transient failures while avoiding immediate, synchronized retries that amplify outages. An example: retry transient session validation failures with exponential backoff and jitter.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Retry with Backoff", + "reliability", + "retry backoff", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages", + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "Retry", + "with", + "backoff", + "retries", + "transient", + "failures", + "while", + "avoiding", + "immediate", + "synchronized", + "that", + "amplify", + "outages", + "example", + "session", + "validation", + "exponential", + "and", + "jitter" + ], + "aliases": [ + "retry backoff", + "Retry with Backoff" + ], + "tags": [ + "reliability", + "overview", + "code example", + "class diagram", + "trade-offs", + "advantages", + "disadvantages" + ], + "githubPath": "reliability-patterns/retry-backoff", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/retry-backoff", + "demoCodePaths": [ + "reliability-patterns/retry-backoff/src/main/java", + "reliability-patterns/retry-backoff/src/main", + "reliability-patterns/retry-backoff/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Retry with Backoff Pattern

\n

📋 Overview

\n

Retry with backoff retries transient failures while avoiding immediate, synchronized retries that amplify outages.

\n

An example: retry transient session validation failures with exponential backoff and jitter.

\n
\n

💡 Code Example

\n
var retry = RetryExecutor.builder("session-validate")\n    .maxAttempts(5)\n    .baseDelay(Duration.ofMillis(50))\n    .maxDelay(Duration.ofSeconds(1))\n    .jitterRatio(0.2)\n    .build();\n\nretry.execute(() -> callAuthService());\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class RetryExecutor {\n        +builder(name) Builder\n        +execute(op) T\n    }\n    class Builder {\n        +maxAttempts(n) Builder\n        +baseDelay(d) Builder\n        +maxDelay(d) Builder\n        +jitterRatio(r) Builder\n        +retryOn(p) Builder\n        +build() RetryExecutor\n    }\n    Builder ..> RetryExecutor : builds\n
\n

\"RetryExecutor

\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Recovers from transient failures
  • \n
  • Reduces retry storms via backoff/jitter
  • \n
\n

Disadvantages ❌

\n
    \n
  • Can increase latency if used for non-transient errors
  • \n
  • Needs strict limits (max attempts, max delay)
  • \n
\n", + "contentMarkdown": "# Retry with Backoff Pattern\n\n## 📋 Overview\n\n**Retry with backoff** retries transient failures while avoiding immediate, synchronized retries that amplify outages.\n\nAn example: retry transient **session validation** failures with exponential backoff and jitter.\n\n---\n\n## 💡 Code Example\n\n```java\nvar retry = RetryExecutor.builder(\"session-validate\")\n .maxAttempts(5)\n .baseDelay(Duration.ofMillis(50))\n .maxDelay(Duration.ofSeconds(1))\n .jitterRatio(0.2)\n .build();\n\nretry.execute(() -> callAuthService());\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class RetryExecutor {\n +builder(name) Builder\n +execute(op) T\n }\n class Builder {\n +maxAttempts(n) Builder\n +baseDelay(d) Builder\n +maxDelay(d) Builder\n +jitterRatio(r) Builder\n +retryOn(p) Builder\n +build() RetryExecutor\n }\n Builder ..> RetryExecutor : builds\n```\n\n![RetryExecutor class diagram](retry-backoff-class-diagram.png)\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Recovers from transient failures\n- Reduces retry storms via backoff/jitter\n\n### Disadvantages ❌\n- Can increase latency if used for non-transient errors\n- Needs strict limits (max attempts, max delay)", + "relatedPatternIds": [ + "bulkhead", + "circuit-breaker", + "timeout-deadline-propagation", + "hedge-requests" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌" + ], + "excerpt": "Retry with Backoff Pattern 📋 Overview Retry with backoff retries transient failures while avoiding immediate, synchronized retries that amplify outages. An example: retry transient session validation failures with exponential backoff and jitter. 📊 Class Diag", + "featured": true + }, + { + "id": "timeout-deadline-propagation", + "slug": "timeout-deadline-propagation", + "name": "Timeout & Deadline Propagation", + "category": "reliability", + "summary": "Deadline propagation uses a single end to end time budget that is passed to all downstream calls. Each call uses the remaining budget so the system fails fast and predictably.", + "intent": "Deadline propagation uses a single end to end time budget that is passed to all downstream calls. Each call uses the remaining budget so the system fails fast and predictably. An example: a “join matchmaking” request has a 200ms budget across multiple services.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Timeout & Deadline Propagation", + "reliability", + "timeout deadline propagation", + "Timeout and Deadline Propagation", + "overview", + "code example", + "class diagram", + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram", + "Deadline", + "propagation", + "uses", + "single", + "end", + "time", + "budget", + "that", + "passed", + "all", + "downstream", + "calls", + "Each", + "call", + "the", + "remaining", + "system", + "fails", + "fast", + "and", + "predictably", + "example", + "join", + "matchmaking", + "request", + "has", + "200ms", + "across", + "multiple", + "services" + ], + "aliases": [ + "timeout deadline propagation", + "Timeout & Deadline Propagation", + "Timeout and Deadline Propagation" + ], + "tags": [ + "reliability", + "overview", + "code example", + "class diagram" + ], + "githubPath": "reliability-patterns/timeout-deadline-propagation", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/reliability-patterns/timeout-deadline-propagation", + "demoCodePaths": [ + "reliability-patterns/timeout-deadline-propagation/src/main/java", + "reliability-patterns/timeout-deadline-propagation/src/main", + "reliability-patterns/timeout-deadline-propagation/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Timeout & Deadline Propagation Pattern

\n

📋 Overview

\n

Deadline propagation uses a single end-to-end time budget that is passed to all downstream calls. Each call uses the remaining budget so the system fails fast and predictably.

\n

An example: a “join matchmaking” request has a 200ms budget across multiple services.

\n
\n

💡 Code Example

\n
Deadline deadline = Deadline.after(Duration.ofMillis(200));\n\ndeadline.throwIfExpired("pre-check");\ncallProfile(deadline.remaining());\n\ndeadline.throwIfExpired("matchmaking");\ncallMatchmaking(deadline.remaining());\n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Deadline {\n        +after(timeout) Deadline\n        +remaining() Duration\n        +throwIfExpired(context)\n    }\n    class DeadlineExceededException\n    Deadline ..> DeadlineExceededException : throws\n
\n

\"Deadline

\n", + "contentMarkdown": "# Timeout & Deadline Propagation Pattern\n\n## 📋 Overview\n\n**Deadline propagation** uses a single end-to-end time budget that is passed to all downstream calls. Each call uses the *remaining* budget so the system fails fast and predictably.\n\nAn example: a “join matchmaking” request has a 200ms budget across multiple services.\n\n---\n\n## 💡 Code Example\n\n```java\nDeadline deadline = Deadline.after(Duration.ofMillis(200));\n\ndeadline.throwIfExpired(\"pre-check\");\ncallProfile(deadline.remaining());\n\ndeadline.throwIfExpired(\"matchmaking\");\ncallMatchmaking(deadline.remaining());\n```\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Deadline {\n +after(timeout) Deadline\n +remaining() Duration\n +throwIfExpired(context)\n }\n class DeadlineExceededException\n Deadline ..> DeadlineExceededException : throws\n```\n\n![Deadline class diagram](deadline-class-diagram.png)", + "relatedPatternIds": [ + "bulkhead", + "rate-limiter", + "hedge-requests", + "idempotency-keys" + ], + "categoryLabel": "Reliability", + "headingIndex": [ + "📋 Overview", + "💡 Code Example", + "📊 Class Diagram" + ], + "excerpt": "Timeout & Deadline Propagation Pattern 📋 Overview Deadline propagation uses a single end to end time budget that is passed to all downstream calls. Each call uses the remaining budget so the system fails fast and predictably. An example: a “join matchmaking” ", + "featured": false + }, + { + "id": "filter", + "slug": "filter", + "name": "Filter", + "category": "miscellaneous", + "summary": "The Filter pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner.", + "intent": "The Filter pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Filter", + "miscellaneous", + "criteria", + "criteria pattern", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "provides", + "way", + "collections", + "objects", + "using", + "different", + "flexible", + "and", + "reusable", + "manner" + ], + "aliases": [ + "filter", + "criteria", + "criteria pattern" + ], + "tags": [ + "miscellaneous", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "miscellaneous-patterns/filter", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/miscellaneous-patterns/filter", + "demoCodePaths": [ + "miscellaneous-patterns/filter/src/main/java", + "miscellaneous-patterns/filter/src/main", + "miscellaneous-patterns/filter/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Filter Pattern

\n

📋 Overview

\n

The Filter pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Filter collections by different criteria
  • \n
  • Combine multiple filter criteria
  • \n
  • Avoid multiple if-else statements
  • \n
  • Enable reusable filter components
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
CriteriaDefines filtering interface
ConcreteCriteriaImplements specific filter logic
FilterApplies criteria to collection
\n
\n

💡 Implementation

\n
    \n
  • Each filter criterion is a separate component
  • \n
  • Filters can be combined/chained
  • \n
  • Enables dynamic filtering logic
  • \n
  • Reusable and testable filters
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Criteria {\n        <<interface>>\n        +meetCriteria(items)\n    }\n    class ConcreteCriteriaA\n    class ConcreteCriteriaB\n    class AndCriteria\n    class OrCriteria\n    Client --> Criteria\n    Criteria <|-- ConcreteCriteriaA\n    Criteria <|-- ConcreteCriteriaB\n    Criteria <|-- AndCriteria\n    Criteria <|-- OrCriteria\n    AndCriteria --> Criteria\n    OrCriteria --> Criteria\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Criteria: meetCriteria(items)\n    Criteria-->>Client: filteredItems\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Flexible filtering logic
  • \n
  • Reusable criteria
  • \n
  • Easy combination of filters
  • \n
  • Clear separation of concerns
  • \n
  • Testable filter logic
  • \n
\n

Disadvantages ❌

\n
    \n
  • Additional classes required
  • \n
  • Performance with many filters
  • \n
  • Memory overhead for criteria objects
  • \n
  • Learning curve
  • \n
  • Over-engineering for simple cases
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Database query builders
  • \n
  • Collection filtering
  • \n
  • Stream filtering
  • \n
  • Search functionality
  • \n
  • Data validation chains
  • \n
\n
\n

📚 References

\n
    \n
  • Criteria Pattern
  • \n
  • Chain of Responsibility Pattern
  • \n
\n", + "contentMarkdown": "# Filter Pattern\n\n## 📋 Overview\n\nThe **Filter** pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Filter collections by different criteria\n- Combine multiple filter criteria\n- Avoid multiple if-else statements\n- Enable reusable filter components\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Criteria | Defines filtering interface |\n| ConcreteCriteria | Implements specific filter logic |\n| Filter | Applies criteria to collection |\n\n---\n\n## 💡 Implementation\n\n- Each filter criterion is a separate component\n- Filters can be combined/chained\n- Enables dynamic filtering logic\n- Reusable and testable filters\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Criteria {\n <>\n +meetCriteria(items)\n }\n class ConcreteCriteriaA\n class ConcreteCriteriaB\n class AndCriteria\n class OrCriteria\n Client --> Criteria\n Criteria <|-- ConcreteCriteriaA\n Criteria <|-- ConcreteCriteriaB\n Criteria <|-- AndCriteria\n Criteria <|-- OrCriteria\n AndCriteria --> Criteria\n OrCriteria --> Criteria\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Criteria: meetCriteria(items)\n Criteria-->>Client: filteredItems\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Flexible filtering logic\n- Reusable criteria\n- Easy combination of filters\n- Clear separation of concerns\n- Testable filter logic\n\n### Disadvantages ❌\n- Additional classes required\n- Performance with many filters\n- Memory overhead for criteria objects\n- Learning curve\n- Over-engineering for simple cases\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Database query builders\n- Collection filtering\n- Stream filtering\n- Search functionality\n- Data validation chains\n\n---\n\n## 📚 References\n\n- Criteria Pattern\n- Chain of Responsibility Pattern", + "relatedPatternIds": [ + "lazy-sequence", + "servant", + "state-machine", + "iterator" + ], + "categoryLabel": "Miscellaneous", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Filter Pattern 📋 Overview The Filter pattern (or Criteria pattern) provides a way to filter collections of objects using different criteria in a flexible and reusable manner. 👥 Roles & Responsibilities Role Responsibility Criteria Defines filtering interface", + "featured": false + }, + { + "id": "lazy-sequence", + "slug": "lazy-sequence", + "name": "Lazy Sequence", + "category": "miscellaneous", + "summary": "The Lazy Sequence pattern defers sequence element computation until they're actually accessed, enabling efficient processing of potentially infinite sequences.", + "intent": "The Lazy Sequence pattern defers sequence element computation until they're actually accessed, enabling efficient processing of potentially infinite sequences.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Lazy Sequence", + "miscellaneous", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Lazy", + "Sequence", + "pattern", + "defers", + "element", + "computation", + "until", + "they", + "actually", + "accessed", + "enabling", + "efficient", + "processing", + "potentially", + "infinite", + "sequences" + ], + "aliases": [ + "lazy sequence" + ], + "tags": [ + "miscellaneous", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "miscellaneous-patterns/lazy-sequence", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/miscellaneous-patterns/lazy-sequence", + "demoCodePaths": [ + "miscellaneous-patterns/lazy-sequence/src/main/java", + "miscellaneous-patterns/lazy-sequence/src/main", + "miscellaneous-patterns/lazy-sequence/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Lazy Sequence Pattern

\n

📋 Overview

\n

The Lazy Sequence pattern defers sequence element computation until they’re actually accessed, enabling efficient processing of potentially infinite sequences.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Defer expensive computations
  • \n
  • Handle potentially infinite sequences
  • \n
  • Support streaming data processing
  • \n
  • Reduce memory usage
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
LazySequenceDefers element computation
ElementGeneratorGenerates individual elements
ClientAccesses elements on demand
\n
\n

💡 Implementation

\n
    \n
  • Elements computed on first access
  • \n
  • Caching computed results
  • \n
  • Support for infinite sequences
  • \n
  • Memory-efficient processing
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class LazySequence {\n        -cache: Map\n        -generator: ElementGenerator\n        +get(index)\n    }\n    class ElementGenerator {\n        <<interface>>\n        +compute(index)\n    }\n    Client --> LazySequence\n    LazySequence --> ElementGenerator\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>LazySequence: get(index)\n    alt cached\n        LazySequence-->>Client: element\n    else not cached\n        LazySequence->>ElementGenerator: compute(index)\n        ElementGenerator-->>LazySequence: element\n        LazySequence-->>Client: element\n    end\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Deferred expensive computations
  • \n
  • Memory efficient
  • \n
  • Support infinite sequences
  • \n
  • Streaming processing
  • \n
  • Computation on demand
  • \n
\n

Disadvantages ❌

\n
    \n
  • Harder to understand
  • \n
  • Non-deterministic timing
  • \n
  • Caching overhead
  • \n
  • Debugging complexity
  • \n
  • First-access latency
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Stream API implementations
  • \n
  • Iterator patterns
  • \n
  • Reactive programming
  • \n
  • Data pipeline processing
  • \n
  • Infinite sequence generation
  • \n
\n
\n

📚 References

\n
    \n
  • Lazy evaluation patterns
  • \n
  • Functional programming concepts
  • \n
  • Stream processing
  • \n
\n", + "contentMarkdown": "# Lazy Sequence Pattern\n\n## 📋 Overview\n\nThe **Lazy Sequence** pattern defers sequence element computation until they're actually accessed, enabling efficient processing of potentially infinite sequences.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Defer expensive computations\n- Handle potentially infinite sequences\n- Support streaming data processing\n- Reduce memory usage\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| LazySequence | Defers element computation |\n| ElementGenerator | Generates individual elements |\n| Client | Accesses elements on demand |\n\n---\n\n## 💡 Implementation\n\n- Elements computed on first access\n- Caching computed results\n- Support for infinite sequences\n- Memory-efficient processing\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class LazySequence {\n -cache: Map\n -generator: ElementGenerator\n +get(index)\n }\n class ElementGenerator {\n <>\n +compute(index)\n }\n Client --> LazySequence\n LazySequence --> ElementGenerator\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>LazySequence: get(index)\n alt cached\n LazySequence-->>Client: element\n else not cached\n LazySequence->>ElementGenerator: compute(index)\n ElementGenerator-->>LazySequence: element\n LazySequence-->>Client: element\n end\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Deferred expensive computations\n- Memory efficient\n- Support infinite sequences\n- Streaming processing\n- Computation on demand\n\n### Disadvantages ❌\n- Harder to understand\n- Non-deterministic timing\n- Caching overhead\n- Debugging complexity\n- First-access latency\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Stream API implementations\n- Iterator patterns\n- Reactive programming\n- Data pipeline processing\n- Infinite sequence generation\n\n---\n\n## 📚 References\n\n- Lazy evaluation patterns\n- Functional programming concepts\n- Stream processing", + "relatedPatternIds": [ + "servant", + "filter", + "interpreter", + "iterator" + ], + "categoryLabel": "Miscellaneous", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Lazy Sequence Pattern 📋 Overview The Lazy Sequence pattern defers sequence element computation until they're actually accessed, enabling efficient processing of potentially infinite sequences. 👥 Roles & Responsibilities Role Responsibility LazySequence Defer", + "featured": false + }, + { + "id": "method-object", + "slug": "method-object", + "name": "Method Object", + "category": "miscellaneous", + "summary": "The Method Object pattern converts a method into an object, enabling flexible method parameter passing and invocation.", + "intent": "The Method Object pattern converts a method into an object, enabling flexible method parameter passing and invocation.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Method Object", + "miscellaneous", + "overview", + "intent", + "roles responsibility", + "class diagram", + "sequence diagram", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibility", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "Method", + "Object", + "pattern", + "converts", + "into", + "enabling", + "flexible", + "parameter", + "passing", + "and", + "invocation" + ], + "aliases": [ + "method object" + ], + "tags": [ + "miscellaneous", + "overview", + "intent", + "roles responsibility", + "class diagram", + "sequence diagram", + "real-world use cases", + "references" + ], + "githubPath": "miscellaneous-patterns/method-object", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/miscellaneous-patterns/method-object", + "demoCodePaths": [ + "miscellaneous-patterns/method-object/src/main/java", + "miscellaneous-patterns/method-object/src/main", + "miscellaneous-patterns/method-object/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Method Object Pattern

\n

📋 Overview

\n

The Method Object pattern converts a method into an object, enabling flexible method parameter passing and invocation.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Complex methods with many parameters
  • \n
  • Need to pass methods as parameters
  • \n
  • Deferred method execution
  • \n
  • Method state management
  • \n
\n
\n

👥 Roles & Responsibility

\n
    \n
  • Encapsulate method as object
  • \n
  • Enable method parameter passing
  • \n
  • Manage method state
  • \n
  • Support deferred execution
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class MethodObject {\n        <<interface>>\n        +execute()\n    }\n    class ConcreteMethodObject\n    class Host {\n        +helper()\n    }\n    Client --> MethodObject\n    MethodObject <|-- ConcreteMethodObject\n    ConcreteMethodObject --> Host\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>MethodObject: execute()\n    MethodObject->>Host: helper()\n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Callback mechanisms
  • \n
  • Command pattern implementation
  • \n
  • Functional programming patterns
  • \n
  • Task queuing systems
  • \n
  • Async operation handlers
  • \n
\n
\n

📚 References

\n
    \n
  • Gang of Four Design Patterns
  • \n
  • Functional programming patterns
  • \n
\n", + "contentMarkdown": "# Method Object Pattern\n\n## 📋 Overview\n\nThe **Method Object** pattern converts a method into an object, enabling flexible method parameter passing and invocation.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Complex methods with many parameters\n- Need to pass methods as parameters\n- Deferred method execution\n- Method state management\n\n---\n\n## 👥 Roles & Responsibility\n\n- Encapsulate method as object\n- Enable method parameter passing\n- Manage method state\n- Support deferred execution\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class MethodObject {\n <>\n +execute()\n }\n class ConcreteMethodObject\n class Host {\n +helper()\n }\n Client --> MethodObject\n MethodObject <|-- ConcreteMethodObject\n ConcreteMethodObject --> Host\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>MethodObject: execute()\n MethodObject->>Host: helper()\n```\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Callback mechanisms\n- Command pattern implementation\n- Functional programming patterns\n- Task queuing systems\n- Async operation handlers\n\n---\n\n## 📚 References\n\n- Gang of Four Design Patterns\n- Functional programming patterns", + "relatedPatternIds": [ + "filter", + "lazy-sequence", + "servant", + "command" + ], + "categoryLabel": "Miscellaneous", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibility", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Method Object Pattern 📋 Overview The Method Object pattern converts a method into an object, enabling flexible method parameter passing and invocation. 👥 Roles & Responsibility Encapsulate method as object Enable method parameter passing Manage method state ", + "featured": false + }, + { + "id": "servant", + "slug": "servant", + "name": "Servant", + "category": "miscellaneous", + "summary": "The Servant pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance.", + "intent": "The Servant pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance.", + "applicability": [], + "tradeOffs": [], + "alternatives": [], + "keywords": [ + "Servant", + "miscellaneous", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references", + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References", + "The", + "pattern", + "defines", + "common", + "functionality", + "separate", + "class", + "that", + "serves", + "multiple", + "classes", + "enabling", + "code", + "reuse", + "without", + "inheritance" + ], + "aliases": [ + "servant" + ], + "tags": [ + "miscellaneous", + "overview", + "intent", + "roles responsibilities", + "implementation", + "class diagram", + "sequence diagram", + "trade-offs", + "advantages", + "disadvantages", + "real-world use cases", + "references" + ], + "githubPath": "miscellaneous-patterns/servant", + "githubUrl": "https://github.com/SaumilP/design-patterns/tree/main/miscellaneous-patterns/servant", + "demoCodePaths": [ + "miscellaneous-patterns/servant/src/main/java", + "miscellaneous-patterns/servant/src/main", + "miscellaneous-patterns/servant/src" + ], + "hasTests": true, + "readingTimeMinutes": 1, + "contentHtml": "

Servant Pattern

\n

📋 Overview

\n

The Servant pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance.

\n
\n

🎯 Intent

\n

Problem Solved:

\n
    \n
  • Provide common functionality to multiple unrelated classes
  • \n
  • Avoid code duplication without inheritance
  • \n
  • Reduce class hierarchy complexity
  • \n
  • Enable flexible behavior sharing
  • \n
\n
\n

👥 Roles & Responsibilities

\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
RoleResponsibility
ServantProvides common functionality
Served ClassesUse servant functionality
ClientInitiates servant behavior
\n
\n

💡 Implementation

\n
    \n
  • Servant contains common operations
  • \n
  • Served classes delegate to servant
  • \n
  • Enables composition over inheritance
  • \n
  • No inheritance relationship required
  • \n
\n
\n

📊 Class Diagram

\n
classDiagram\n    class Client\n    class Servant {\n        +operation(served)\n    }\n    class ServedA\n    class ServedB\n    Client --> Servant\n    Servant --> ServedA\n    Servant --> ServedB\n
\n
\n

🔄 Sequence Diagram

\n
sequenceDiagram\n    actor Client\n    Client->>Servant: operation(served)\n    Servant->>ServedA: doWork()\n    Servant-->>Client: result\n
\n
\n

⚖️ Trade-offs

\n

Advantages ✅

\n
    \n
  • Code reuse without inheritance
  • \n
  • Flexible behavior sharing
  • \n
  • Avoids multiple inheritance
  • \n
  • Clean separation of concerns
  • \n
  • Reusable servant components
  • \n
\n

Disadvantages ❌

\n
    \n
  • Additional object dependencies
  • \n
  • Parameter passing complexity
  • \n
  • Servant state management
  • \n
  • Performance overhead
  • \n
  • Design complexity
  • \n
\n
\n

🌍 Real-World Use Cases

\n
    \n
  • Utility classes
  • \n
  • Shared behavior across unrelated classes
  • \n
  • Cross-cutting concerns
  • \n
  • Aspect-oriented design
  • \n
  • Mixin functionality
  • \n
\n
\n

📚 References

\n
    \n
  • Servant Pattern
  • \n
  • Design Patterns in Practice
  • \n
\n", + "contentMarkdown": "# Servant Pattern\n\n## 📋 Overview\n\nThe **Servant** pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance.\n\n---\n\n## 🎯 Intent\n\n**Problem Solved:**\n- Provide common functionality to multiple unrelated classes\n- Avoid code duplication without inheritance\n- Reduce class hierarchy complexity\n- Enable flexible behavior sharing\n\n---\n\n## 👥 Roles & Responsibilities\n\n| Role | Responsibility |\n|------|-----------------|\n| Servant | Provides common functionality |\n| Served Classes | Use servant functionality |\n| Client | Initiates servant behavior |\n\n---\n\n## 💡 Implementation\n\n- Servant contains common operations\n- Served classes delegate to servant\n- Enables composition over inheritance\n- No inheritance relationship required\n\n---\n\n## 📊 Class Diagram\n\n```mermaid\nclassDiagram\n class Client\n class Servant {\n +operation(served)\n }\n class ServedA\n class ServedB\n Client --> Servant\n Servant --> ServedA\n Servant --> ServedB\n```\n\n---\n\n## 🔄 Sequence Diagram\n\n```mermaid\nsequenceDiagram\n actor Client\n Client->>Servant: operation(served)\n Servant->>ServedA: doWork()\n Servant-->>Client: result\n```\n\n---\n\n## ⚖️ Trade-offs\n\n### Advantages ✅\n- Code reuse without inheritance\n- Flexible behavior sharing\n- Avoids multiple inheritance\n- Clean separation of concerns\n- Reusable servant components\n\n### Disadvantages ❌\n- Additional object dependencies\n- Parameter passing complexity\n- Servant state management\n- Performance overhead\n- Design complexity\n\n---\n\n## 🌍 Real-World Use Cases\n\n- Utility classes\n- Shared behavior across unrelated classes\n- Cross-cutting concerns\n- Aspect-oriented design\n- Mixin functionality\n\n---\n\n## 📚 References\n\n- Servant Pattern\n- Design Patterns in Practice", + "relatedPatternIds": [ + "lazy-sequence", + "filter", + "interpreter", + "mediator" + ], + "categoryLabel": "Miscellaneous", + "headingIndex": [ + "📋 Overview", + "🎯 Intent", + "👥 Roles & Responsibilities", + "💡 Implementation", + "📊 Class Diagram", + "🔄 Sequence Diagram", + "⚖️ Trade-offs", + "Advantages ✅", + "Disadvantages ❌", + "🌍 Real-World Use Cases", + "📚 References" + ], + "excerpt": "Servant Pattern 📋 Overview The Servant pattern defines common functionality in a separate class (servant) that serves multiple classes, enabling code reuse without inheritance. 👥 Roles & Responsibilities Role Responsibility Servant Provides common functional", + "featured": false + } +] diff --git a/site/src/content/related-patterns.json b/site/src/content/related-patterns.json new file mode 100644 index 0000000..63036c6 --- /dev/null +++ b/site/src/content/related-patterns.json @@ -0,0 +1,260 @@ +{ + "abstract-factory": [ + "factory-method", + "prototype", + "builder", + "singleton" + ], + "adapter": [ + "bridge", + "composite", + "decorator", + "facade" + ], + "bridge": [ + "adapter", + "composite", + "decorator", + "facade" + ], + "builder": [ + "singleton", + "abstract-factory", + "factory-method", + "prototype" + ], + "chain": [ + "abstract-factory", + "factory-method", + "adapter", + "bridge" + ], + "command": [ + "strategy", + "chain", + "observer", + "state" + ], + "composite": [ + "adapter", + "bridge", + "decorator", + "facade" + ], + "decorator": [ + "adapter", + "bridge", + "composite", + "facade" + ], + "facade": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "factory-method": [ + "abstract-factory", + "builder", + "singleton", + "prototype" + ], + "flyweight": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "interpreter": [ + "mediator", + "iterator", + "memento", + "visitor" + ], + "iterator": [ + "visitor", + "interpreter", + "memento", + "mediator" + ], + "mediator": [ + "interpreter", + "visitor", + "memento", + "observer" + ], + "memento": [ + "mediator", + "visitor", + "interpreter", + "iterator" + ], + "observer": [ + "state", + "strategy", + "mediator", + "command" + ], + "prototype": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "proxy": [ + "adapter", + "bridge", + "composite", + "decorator" + ], + "singleton": [ + "builder", + "factory-method", + "abstract-factory", + "prototype" + ], + "state": [ + "observer", + "command", + "template-method", + "chain" + ], + "strategy": [ + "command", + "observer", + "template-method", + "mediator" + ], + "template-method": [ + "observer", + "state", + "strategy", + "chain" + ], + "visitor": [ + "mediator", + "iterator", + "memento", + "interpreter" + ], + "model-view-presenter": [ + "state-machine", + "service-locator", + "mediator", + "interpreter" + ], + "service-locator": [ + "model-view-presenter", + "state-machine", + "singleton", + "abstract-factory" + ], + "state-machine": [ + "model-view-presenter", + "service-locator", + "filter", + "mediator" + ], + "cqrs": [ + "transactional-outbox", + "saga", + "pipes-and-filters", + "rate-limiter" + ], + "pipes-and-filters": [ + "command", + "interpreter", + "mediator", + "memento" + ], + "saga": [ + "transactional-outbox", + "cqrs", + "pipes-and-filters", + "rate-limiter" + ], + "transactional-outbox": [ + "saga", + "cqrs", + "pipes-and-filters", + "observer" + ], + "bulkhead": [ + "rate-limiter", + "circuit-breaker", + "retry-backoff", + "hedge-requests" + ], + "circuit-breaker": [ + "rate-limiter", + "bulkhead", + "builder", + "abstract-factory" + ], + "double-checked-locking": [ + "nullobject", + "circuit-breaker", + "interpreter", + "mediator" + ], + "hedge-requests": [ + "bulkhead", + "rate-limiter", + "retry-backoff", + "cqrs" + ], + "idempotency-keys": [ + "hedge-requests", + "retry-backoff", + "timeout-deadline-propagation", + "rate-limiter" + ], + "nullobject": [ + "interpreter", + "iterator", + "filter", + "servant" + ], + "rate-limiter": [ + "circuit-breaker", + "bulkhead", + "nullobject", + "saga" + ], + "retry-backoff": [ + "bulkhead", + "circuit-breaker", + "timeout-deadline-propagation", + "hedge-requests" + ], + "timeout-deadline-propagation": [ + "bulkhead", + "rate-limiter", + "hedge-requests", + "idempotency-keys" + ], + "filter": [ + "lazy-sequence", + "servant", + "state-machine", + "iterator" + ], + "lazy-sequence": [ + "servant", + "filter", + "interpreter", + "iterator" + ], + "method-object": [ + "filter", + "lazy-sequence", + "servant", + "command" + ], + "servant": [ + "lazy-sequence", + "filter", + "interpreter", + "mediator" + ] +} diff --git a/site/src/data/categories.ts b/site/src/data/categories.ts new file mode 100644 index 0000000..af2b826 --- /dev/null +++ b/site/src/data/categories.ts @@ -0,0 +1,63 @@ +import type { PatternCategory } from "../types/pattern"; + +export interface CategoryDefinition { + id: PatternCategory; + label: string; + shortLabel: string; + description: string; + accentClass: string; + icon: string; + repoFolder: string; +} + +export const categories: CategoryDefinition[] = [ + { + id: "gof", + label: "GoF", + shortLabel: "GoF", + description: "Creational, structural, and behavioral fundamentals.", + accentClass: "from-cyan-500/20 via-sky-500/10 to-transparent", + icon: "hexagon", + repoFolder: "gof-patterns", + }, + { + id: "architectural", + label: "Architectural", + shortLabel: "Arch", + description: "System boundary, layering, and orchestration patterns.", + accentClass: "from-violet-500/20 via-fuchsia-500/10 to-transparent", + icon: "layers", + repoFolder: "architectural-patterns", + }, + { + id: "enterprise-integration", + label: "Enterprise Integration", + shortLabel: "EIP", + description: "Messaging, consistency, and workflow patterns.", + accentClass: "from-emerald-500/20 via-lime-500/10 to-transparent", + icon: "flow", + repoFolder: "enterprise-integration-patterns", + }, + { + id: "reliability", + label: "Reliability", + shortLabel: "Rel", + description: "Resilience, throttling, retries, and fault isolation.", + accentClass: "from-amber-500/20 via-orange-500/10 to-transparent", + icon: "shield", + repoFolder: "reliability-patterns", + }, + { + id: "miscellaneous", + label: "Miscellaneous", + shortLabel: "Misc", + description: "Useful patterns that do not sit in one classical bucket.", + accentClass: "from-slate-500/20 via-zinc-500/10 to-transparent", + icon: "nodes", + repoFolder: "miscellaneous-patterns", + }, +]; + +export const categoryMap = Object.fromEntries( + categories.map((category) => [category.id, category]), +) as Record; diff --git a/site/src/lib/github.ts b/site/src/lib/github.ts new file mode 100644 index 0000000..094de3e --- /dev/null +++ b/site/src/lib/github.ts @@ -0,0 +1,3 @@ +export const repositoryUrl = "https://github.com/SaumilP/design-patterns"; +export const contributionUrl = `${repositoryUrl}/blob/main/CONTRIBUTING.md`; +export const pagesUrl = "https://saumilp.github.io/design-patterns"; diff --git a/site/src/lib/markdown.ts b/site/src/lib/markdown.ts new file mode 100644 index 0000000..c13db11 --- /dev/null +++ b/site/src/lib/markdown.ts @@ -0,0 +1,11 @@ +export function stripHtml(value: string): string { + return value.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim(); +} + +export function summarize(value: string, limit = 160): string { + const text = stripHtml(value); + if (text.length <= limit) { + return text; + } + return `${text.slice(0, limit).trim()}...`; +} diff --git a/site/src/lib/search.ts b/site/src/lib/search.ts new file mode 100644 index 0000000..4100827 --- /dev/null +++ b/site/src/lib/search.ts @@ -0,0 +1,158 @@ +import { Document } from "flexsearch"; +import type { PatternCategory, PatternRecord } from "../types/pattern"; + +export interface SearchResult { + pattern: PatternRecord; + score: number; +} + +export const intentChips = [ + "Object creation", + "Behavior selection", + "Reliability", + "Integration flow", + "State transitions", +]; + +function levenshtein(left: string, right: string): number { + const a = left.toLowerCase(); + const b = right.toLowerCase(); + const matrix = Array.from({ length: a.length + 1 }, () => new Array(b.length + 1).fill(0)); + + for (let i = 0; i <= a.length; i += 1) matrix[i][0] = i; + for (let j = 0; j <= b.length; j += 1) matrix[0][j] = j; + + for (let i = 1; i <= a.length; i += 1) { + for (let j = 1; j <= b.length; j += 1) { + const cost = a[i - 1] === b[j - 1] ? 0 : 1; + matrix[i][j] = Math.min( + matrix[i - 1][j] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j - 1] + cost, + ); + } + } + + return matrix[a.length][b.length]; +} + +function normalizedCategoryText(pattern: PatternRecord) { + return `${pattern.category} ${pattern.categoryLabel}`.toLowerCase(); +} + +export function createPatternSearch(patterns: PatternRecord[]) { + const document = new Document({ + charset: "latin:advanced", + tokenize: "forward", + resolution: 9, + document: { + id: "id", + store: true, + index: [ + { field: "name", tokenize: "forward" }, + { field: "aliases", tokenize: "forward" }, + { field: "keywords", tokenize: "forward" }, + { field: "tags", tokenize: "forward" }, + { field: "summary", tokenize: "full" }, + { field: "intent", tokenize: "full" }, + { field: "contentMarkdown", tokenize: "strict" }, + ], + }, + }); + + for (const pattern of patterns) { + document.add(pattern); + } + + return { + search(query: string, categoryFilter?: PatternCategory | "all") { + const trimmed = query.trim(); + const lowerQuery = trimmed.toLowerCase(); + const scores = new Map(); + + const addScore = (patternId: string, value: number) => { + scores.set(patternId, (scores.get(patternId) ?? 0) + value); + }; + + if (trimmed.length > 1) { + const results = document.search(trimmed, { enrich: true, limit: 24, suggest: true }); + for (const resultSet of results) { + const fieldWeight = + resultSet.field === "name" + ? 20 + : resultSet.field === "aliases" + ? 15 + : resultSet.field === "keywords" + ? 12 + : resultSet.field === "tags" + ? 10 + : resultSet.field === "summary" + ? 8 + : resultSet.field === "intent" + ? 7 + : 4; + + for (const item of resultSet.result) { + addScore(String(item.id), fieldWeight); + } + } + } + + for (const pattern of patterns) { + const name = pattern.name.toLowerCase(); + const aliases = pattern.aliases.map((alias) => alias.toLowerCase()); + const keywords = pattern.keywords.map((keyword) => keyword.toLowerCase()); + const categoryText = normalizedCategoryText(pattern); + + if (!trimmed) { + addScore(pattern.id, pattern.featured ? 20 : 1); + } + + if (name === lowerQuery) addScore(pattern.id, 200); + if (name.startsWith(lowerQuery)) addScore(pattern.id, 120); + if (name.includes(lowerQuery) && lowerQuery) addScore(pattern.id, 70); + if (aliases.includes(lowerQuery)) addScore(pattern.id, 130); + if (aliases.some((alias) => alias.startsWith(lowerQuery) && lowerQuery)) addScore(pattern.id, 80); + if (keywords.some((keyword) => keyword.includes(lowerQuery) && lowerQuery)) addScore(pattern.id, 40); + if (categoryText.includes(lowerQuery) && lowerQuery) addScore(pattern.id, 25); + + const fuzzyDistance = Math.min( + levenshtein(lowerQuery, name), + ...aliases.map((alias) => levenshtein(lowerQuery, alias)), + ); + if (lowerQuery && fuzzyDistance <= 2) { + addScore(pattern.id, 60 - fuzzyDistance * 15); + } + + if (categoryFilter && categoryFilter !== "all" && pattern.category === categoryFilter) { + addScore(pattern.id, 35); + } + } + + return patterns + .filter((pattern) => categoryFilter === "all" || !categoryFilter || pattern.category === categoryFilter) + .map((pattern) => ({ + pattern, + score: scores.get(pattern.id) ?? 0, + })) + .filter((entry) => (trimmed ? entry.score > 0 : true)) + .sort((left, right) => right.score - left.score || left.pattern.name.localeCompare(right.pattern.name)); + }, + suggestions(query: string) { + const lowerQuery = query.trim().toLowerCase(); + if (!lowerQuery) { + return intentChips; + } + + const values = new Set(); + for (const pattern of patterns) { + if (pattern.name.toLowerCase().includes(lowerQuery)) values.add(pattern.name); + if (pattern.categoryLabel.toLowerCase().includes(lowerQuery)) values.add(pattern.categoryLabel); + for (const keyword of pattern.keywords) { + if (keyword.toLowerCase().includes(lowerQuery)) values.add(keyword); + } + } + return [...values].slice(0, 6); + }, + }; +} diff --git a/site/src/lib/seo.ts b/site/src/lib/seo.ts new file mode 100644 index 0000000..44d9a63 --- /dev/null +++ b/site/src/lib/seo.ts @@ -0,0 +1,47 @@ +import { useEffect } from "react"; +import { pagesUrl } from "./github"; + +function ensureMeta(selector: string, factory: () => HTMLMetaElement | HTMLLinkElement) { + let element = document.head.querySelector(selector) as HTMLMetaElement | HTMLLinkElement | null; + if (!element) { + element = factory(); + document.head.appendChild(element); + } + return element; +} + +export function useSeo(args: { title: string; description: string; path: string }) { + const { title, description, path } = args; + + useEffect(() => { + document.title = `${title} | Design Patterns`; + + const metaDescription = ensureMeta('meta[name="description"]', () => { + const meta = document.createElement("meta"); + meta.name = "description"; + return meta; + }) as HTMLMetaElement; + metaDescription.content = description; + + const ogTitle = ensureMeta('meta[property="og:title"]', () => { + const meta = document.createElement("meta"); + meta.setAttribute("property", "og:title"); + return meta; + }) as HTMLMetaElement; + ogTitle.content = `${title} | Design Patterns`; + + const ogDescription = ensureMeta('meta[property="og:description"]', () => { + const meta = document.createElement("meta"); + meta.setAttribute("property", "og:description"); + return meta; + }) as HTMLMetaElement; + ogDescription.content = description; + + const canonical = ensureMeta('link[rel="canonical"]', () => { + const link = document.createElement("link"); + link.rel = "canonical"; + return link; + }) as HTMLLinkElement; + canonical.href = `${pagesUrl}${path}`; + }, [description, path, title]); +} diff --git a/site/src/main.tsx b/site/src/main.tsx new file mode 100644 index 0000000..d522970 --- /dev/null +++ b/site/src/main.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { BrowserRouter } from "react-router-dom"; +import App from "./App"; +import "./styles/index.css"; +import "./styles/prose.css"; + +const redirect = window.sessionStorage.getItem("gh-pages-path"); +if (redirect && window.location.pathname === "/design-patterns/") { + window.history.replaceState(null, "", `/design-patterns${redirect}`); + window.sessionStorage.removeItem("gh-pages-path"); +} + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + , +); diff --git a/site/src/pages/AboutPage.tsx b/site/src/pages/AboutPage.tsx new file mode 100644 index 0000000..fefa26f --- /dev/null +++ b/site/src/pages/AboutPage.tsx @@ -0,0 +1,31 @@ +import { contributionUrl, repositoryUrl } from "../lib/github"; +import { useSeo } from "../lib/seo"; +import { Button } from "../components/common/Button"; + +export function AboutPage() { + useSeo({ + title: "About", + description: "About the Design Patterns in Java catalog and repository.", + path: "/about", + }); + + return ( +
+
+
About
+

Repository-first documentation

+

+ This site treats the repository folders as the content source. Every card and detail page is generated from the pattern README files, with no backend and no duplicated site-specific content to maintain. +

+
+ + +
+
+
+ ); +} diff --git a/site/src/pages/CatalogPage.tsx b/site/src/pages/CatalogPage.tsx new file mode 100644 index 0000000..92830c7 --- /dev/null +++ b/site/src/pages/CatalogPage.tsx @@ -0,0 +1,87 @@ +import { categories, categoryMap } from "../data/categories"; +import { intentChips } from "../lib/search"; +import { useSeo } from "../lib/seo"; +import type { PatternCategory, PatternRecord } from "../types/pattern"; +import { CategoryFilterBar } from "../components/filters/CategoryFilterBar"; +import { SearchBar } from "../components/search/SearchBar"; +import { SearchResults } from "../components/search/SearchResults"; + +export function CatalogPage(props: { + patterns: PatternRecord[]; + total: number; + query: string; + category: PatternCategory | "all"; + onQueryChange: (value: string) => void; + onCategoryChange: (value: PatternCategory | "all") => void; + onIntentClick: (value: string) => void; + onOpenPalette: () => void; +}) { + const { patterns, total, query, category, onQueryChange, onCategoryChange, onIntentClick, onOpenPalette } = props; + + useSeo({ + title: category === "all" ? "Explore Patterns" : `${categoryMap[category].label} Patterns`, + description: + category === "all" + ? "Browse the full Java design pattern catalog with fuzzy search and category filters." + : `Browse ${categoryMap[category].label} patterns with summaries, source links, and trade-offs.`, + path: category === "all" ? "/patterns" : `/categories/${category}`, + }); + + return ( +
+
+
+
+
Catalog
+

Search the full pattern index

+

+ Exact names, prefixes, aliases, category terms, and intent-style queries all resolve against the generated repository index. +

+
+ +
+ +
+ {intentChips.map((chip) => ( + + ))} +
+ +
+ +
+
+ +
+
+
+ Showing {patterns.length} of{" "} + {total} patterns +
+
+ {categories.map((item) => ( + + ))} +
+
+ +
+
+ ); +} diff --git a/site/src/pages/HomePage.tsx b/site/src/pages/HomePage.tsx new file mode 100644 index 0000000..89c2c0c --- /dev/null +++ b/site/src/pages/HomePage.tsx @@ -0,0 +1,132 @@ +import { Link } from "react-router-dom"; +import { categories } from "../data/categories"; +import { intentChips } from "../lib/search"; +import { useSeo } from "../lib/seo"; +import type { PatternRecord } from "../types/pattern"; +import { Button } from "../components/common/Button"; +import { SearchBar } from "../components/search/SearchBar"; +import { SearchResults } from "../components/search/SearchResults"; +import { repositoryUrl } from "../lib/github"; + +export function HomePage(props: { + featuredPatterns: PatternRecord[]; + query: string; + onQueryChange: (value: string) => void; + onIntentClick: (value: string) => void; + onOpenPalette: () => void; + stats: { + totalPatterns: number; + totalCategories: number; + examplesIncluded: number; + testedPatterns: number; + }; +}) { + const { featuredPatterns, query, onQueryChange, onIntentClick, onOpenPalette, stats } = props; + + useSeo({ + title: "Practical Java Design Patterns", + description: "Runnable examples, trade-offs, and architecture notes in one searchable catalog.", + path: "/", + }); + + return ( +
+
+
+
+ Modern GitHub Pages catalog +
+

+ Practical Java Design Patterns +

+

+ Runnable examples, trade-offs, and architecture notes in one searchable catalog. +

+
+ + Explore Patterns + + +
+
+ +
+
Command search
+
+ +
+
+ {intentChips.map((chip) => ( + + ))} +
+
+
+ +
+
+
Patterns
+
{stats.totalPatterns}
+
+
+
Categories
+
{stats.totalCategories}
+
+
+
Examples
+
{stats.examplesIncluded}
+
+
+
Tested
+
{stats.testedPatterns}
+
+
+ +
+
+
+
Categories
+

Explore by pattern family

+
+ + See full catalog + +
+ +
+ {categories.map((category) => ( + +
{category.shortLabel}
+
{category.label}
+

{category.description}

+ + ))} +
+
+ +
+
+
Featured patterns
+

Strong starting points

+
+ +
+
+ ); +} diff --git a/site/src/pages/NotFoundPage.tsx b/site/src/pages/NotFoundPage.tsx new file mode 100644 index 0000000..be2c50a --- /dev/null +++ b/site/src/pages/NotFoundPage.tsx @@ -0,0 +1,24 @@ +import { Link } from "react-router-dom"; +import { useSeo } from "../lib/seo"; + +export function NotFoundPage() { + useSeo({ + title: "Not Found", + description: "The requested route does not match a generated pattern page.", + path: "/404", + }); + + return ( +
+
404
+

Pattern route not found

+

Use the catalog or command palette to jump back into the generated index.

+ + Back to catalog + +
+ ); +} diff --git a/site/src/pages/PatternPage.tsx b/site/src/pages/PatternPage.tsx new file mode 100644 index 0000000..db2c5bb --- /dev/null +++ b/site/src/pages/PatternPage.tsx @@ -0,0 +1,140 @@ +import type { PatternRecord } from "../types/pattern"; +import { contributionUrl } from "../lib/github"; +import { summarize } from "../lib/markdown"; +import { useSeo } from "../lib/seo"; +import { Button } from "../components/common/Button"; +import { CategoryBadge } from "../components/patterns/CategoryBadge"; +import { RelatedPatterns } from "../components/patterns/RelatedPatterns"; + +export function PatternPage(props: { pattern: PatternRecord; related: PatternRecord[] }) { + const { pattern, related } = props; + + useSeo({ + title: pattern.name, + description: pattern.summary || summarize(pattern.contentHtml ?? "", 170), + path: `/patterns/${pattern.slug}`, + }); + + return ( +
+
+
+ + {pattern.subcategory ? ( + + {pattern.subcategory} + + ) : null} + {pattern.hasTests ? ( + + Has tests + + ) : null} +
+ +

+ {pattern.name} +

+

{pattern.summary}

+ +
+ + +
+ +
+
+ + +
+ ); +} diff --git a/site/src/styles/index.css b/site/src/styles/index.css new file mode 100644 index 0000000..0592456 --- /dev/null +++ b/site/src/styles/index.css @@ -0,0 +1,40 @@ +@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Manrope:wght@400;500;600;700;800&family=Space+Grotesk:wght@500;700&display=swap"); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + color-scheme: dark; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + min-width: 320px; + background: #020617; + color: #f8fafc; + font-family: "Manrope", ui-sans-serif, system-ui; +} + +a { + color: inherit; + text-decoration: none; +} + +button, +input { + font: inherit; +} + +* { + box-sizing: border-box; +} + +*:focus-visible { + outline: 2px solid #67e8f9; + outline-offset: 2px; +} diff --git a/site/src/styles/prose.css b/site/src/styles/prose.css new file mode 100644 index 0000000..58c046c --- /dev/null +++ b/site/src/styles/prose.css @@ -0,0 +1,72 @@ +.prose-shell { + color: #cbd5e1; +} + +.prose-shell h1, +.prose-shell h2, +.prose-shell h3, +.prose-shell h4 { + color: #f8fafc; + font-family: "Space Grotesk", ui-sans-serif, system-ui; + line-height: 1.1; +} + +.prose-shell h2 { + margin-top: 2.5rem; + font-size: 1.9rem; +} + +.prose-shell h3 { + margin-top: 1.75rem; + font-size: 1.3rem; +} + +.prose-shell p, +.prose-shell li { + font-size: 1rem; + line-height: 1.9; +} + +.prose-shell a { + color: #67e8f9; +} + +.prose-shell pre { + overflow-x: auto; + border-radius: 1rem; + border: 1px solid rgba(255, 255, 255, 0.08); + background: #020617; + padding: 1rem; +} + +.prose-shell code { + border-radius: 0.45rem; + background: rgba(255, 255, 255, 0.08); + padding: 0.15rem 0.4rem; + font-family: "JetBrains Mono", monospace; + font-size: 0.9em; +} + +.prose-shell pre code { + padding: 0; + background: transparent; +} + +.prose-shell blockquote { + margin: 1.5rem 0; + border-left: 4px solid #22d3ee; + padding-left: 1rem; + color: #94a3b8; +} + +.prose-shell table { + width: 100%; + border-collapse: collapse; +} + +.prose-shell th, +.prose-shell td { + border: 1px solid rgba(255, 255, 255, 0.08); + padding: 0.75rem; + text-align: left; +} diff --git a/site/src/types/pattern.ts b/site/src/types/pattern.ts new file mode 100644 index 0000000..6ecaa35 --- /dev/null +++ b/site/src/types/pattern.ts @@ -0,0 +1,37 @@ +export type PatternCategory = + | "gof" + | "architectural" + | "enterprise-integration" + | "reliability" + | "miscellaneous"; + +export interface PatternRecord { + id: string; + slug: string; + name: string; + category: PatternCategory; + subcategory?: string; + summary: string; + intent?: string; + problem?: string; + applicability?: string[]; + tradeOffs?: string[]; + alternatives?: string[]; + keywords: string[]; + aliases: string[]; + tags: string[]; + githubPath: string; + githubUrl: string; + demoCodePaths?: string[]; + hasTests?: boolean; + readingTimeMinutes?: number; + contentHtml?: string; + contentMarkdown?: string; + relatedPatternIds?: string[]; + categoryLabel: string; + headingIndex?: string[]; + excerpt?: string; + featured?: boolean; +} + +export type RelatedPatternMap = Record; diff --git a/site/tailwind.config.ts b/site/tailwind.config.ts new file mode 100644 index 0000000..02774c6 --- /dev/null +++ b/site/tailwind.config.ts @@ -0,0 +1,19 @@ +import type { Config } from "tailwindcss"; + +export default { + content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx,html}"], + theme: { + extend: { + fontFamily: { + display: ["Space Grotesk", "ui-sans-serif", "system-ui"], + body: ["Manrope", "ui-sans-serif", "system-ui"], + mono: ["JetBrains Mono", "ui-monospace", "monospace"], + }, + borderRadius: { + xl: "1rem", + "2xl": "1.25rem", + }, + }, + }, + plugins: [require("@tailwindcss/typography")], +} satisfies Config; diff --git a/site/tsconfig.json b/site/tsconfig.json new file mode 100644 index 0000000..5fa7983 --- /dev/null +++ b/site/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ES2022"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "types": ["node"] + }, + "include": ["src", "scripts", "vite.config.ts", "tailwind.config.ts"] +} diff --git a/site/vite.config.ts b/site/vite.config.ts new file mode 100644 index 0000000..3d997e5 --- /dev/null +++ b/site/vite.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + base: "/design-patterns/", + build: { + outDir: "dist", + sourcemap: false, + }, + plugins: [react()], +}); From 6dd01a34409a79e883bc3092c83de29e7be52500 Mon Sep 17 00:00:00 2001 From: Saumil Patel Date: Fri, 6 Mar 2026 23:09:47 +0200 Subject: [PATCH 2/3] Site Design change --- site/package-lock.json | 1358 ++++++++++++++++- site/package.json | 2 + .../pattern-previews/abstract-factory.svg | 32 + site/public/pattern-previews/adapter.svg | 32 + site/public/pattern-previews/bridge.svg | 32 + site/public/pattern-previews/builder.svg | 32 + site/public/pattern-previews/bulkhead.svg | 32 + site/public/pattern-previews/chain.svg | 32 + .../pattern-previews/circuit-breaker.svg | 32 + site/public/pattern-previews/command.svg | 32 + site/public/pattern-previews/composite.svg | 32 + site/public/pattern-previews/cqrs.svg | 32 + site/public/pattern-previews/decorator.svg | 32 + .../double-checked-locking.svg | 32 + site/public/pattern-previews/facade.svg | 32 + .../pattern-previews/factory-method.svg | 32 + site/public/pattern-previews/filter.svg | 32 + site/public/pattern-previews/flyweight.svg | 32 + .../pattern-previews/hedge-requests.svg | 32 + .../pattern-previews/idempotency-keys.svg | 32 + site/public/pattern-previews/interpreter.svg | 32 + site/public/pattern-previews/iterator.svg | 32 + .../public/pattern-previews/lazy-sequence.svg | 32 + site/public/pattern-previews/mediator.svg | 32 + site/public/pattern-previews/memento.svg | 32 + .../public/pattern-previews/method-object.svg | 32 + .../pattern-previews/model-view-presenter.svg | 32 + site/public/pattern-previews/nullobject.svg | 32 + site/public/pattern-previews/observer.svg | 32 + .../pattern-previews/pipes-and-filters.svg | 32 + site/public/pattern-previews/prototype.svg | 32 + site/public/pattern-previews/proxy.svg | 32 + site/public/pattern-previews/rate-limiter.svg | 32 + .../public/pattern-previews/retry-backoff.svg | 32 + site/public/pattern-previews/saga.svg | 32 + site/public/pattern-previews/servant.svg | 32 + .../pattern-previews/service-locator.svg | 32 + site/public/pattern-previews/singleton.svg | 32 + .../public/pattern-previews/state-machine.svg | 32 + site/public/pattern-previews/state.svg | 32 + site/public/pattern-previews/strategy.svg | 32 + .../pattern-previews/template-method.svg | 32 + .../timeout-deadline-propagation.svg | 32 + .../pattern-previews/transactional-outbox.svg | 32 + site/public/pattern-previews/visitor.svg | 32 + site/scripts/build-pattern-index.mjs | 36 +- site/scripts/extract-pattern-metadata.mjs | 27 + site/scripts/generate-pattern-preview.mjs | 131 ++ site/src/App.tsx | 27 +- site/src/components/common/Button.tsx | 6 +- .../components/filters/CategoryFilterBar.tsx | 4 +- site/src/components/layout/AppShell.tsx | 10 +- site/src/components/layout/Footer.tsx | 6 +- site/src/components/layout/Header.tsx | 39 +- .../src/components/patterns/CategoryBadge.tsx | 5 +- site/src/components/patterns/PatternCard.tsx | 46 +- .../components/patterns/RelatedPatterns.tsx | 8 +- site/src/components/search/SearchBar.tsx | 8 +- site/src/components/search/SearchResults.tsx | 8 +- site/src/content/patterns.json | 258 ++-- site/src/data/categories.ts | 28 +- site/src/pages/AboutPage.tsx | 6 +- site/src/pages/CatalogPage.tsx | 20 +- site/src/pages/HomePage.tsx | 50 +- site/src/pages/PatternPage.tsx | 192 ++- site/src/styles/index.css | 134 +- site/src/styles/prose.css | 90 +- site/src/types/pattern.ts | 2 + 68 files changed, 3590 insertions(+), 287 deletions(-) create mode 100644 site/public/pattern-previews/abstract-factory.svg create mode 100644 site/public/pattern-previews/adapter.svg create mode 100644 site/public/pattern-previews/bridge.svg create mode 100644 site/public/pattern-previews/builder.svg create mode 100644 site/public/pattern-previews/bulkhead.svg create mode 100644 site/public/pattern-previews/chain.svg create mode 100644 site/public/pattern-previews/circuit-breaker.svg create mode 100644 site/public/pattern-previews/command.svg create mode 100644 site/public/pattern-previews/composite.svg create mode 100644 site/public/pattern-previews/cqrs.svg create mode 100644 site/public/pattern-previews/decorator.svg create mode 100644 site/public/pattern-previews/double-checked-locking.svg create mode 100644 site/public/pattern-previews/facade.svg create mode 100644 site/public/pattern-previews/factory-method.svg create mode 100644 site/public/pattern-previews/filter.svg create mode 100644 site/public/pattern-previews/flyweight.svg create mode 100644 site/public/pattern-previews/hedge-requests.svg create mode 100644 site/public/pattern-previews/idempotency-keys.svg create mode 100644 site/public/pattern-previews/interpreter.svg create mode 100644 site/public/pattern-previews/iterator.svg create mode 100644 site/public/pattern-previews/lazy-sequence.svg create mode 100644 site/public/pattern-previews/mediator.svg create mode 100644 site/public/pattern-previews/memento.svg create mode 100644 site/public/pattern-previews/method-object.svg create mode 100644 site/public/pattern-previews/model-view-presenter.svg create mode 100644 site/public/pattern-previews/nullobject.svg create mode 100644 site/public/pattern-previews/observer.svg create mode 100644 site/public/pattern-previews/pipes-and-filters.svg create mode 100644 site/public/pattern-previews/prototype.svg create mode 100644 site/public/pattern-previews/proxy.svg create mode 100644 site/public/pattern-previews/rate-limiter.svg create mode 100644 site/public/pattern-previews/retry-backoff.svg create mode 100644 site/public/pattern-previews/saga.svg create mode 100644 site/public/pattern-previews/servant.svg create mode 100644 site/public/pattern-previews/service-locator.svg create mode 100644 site/public/pattern-previews/singleton.svg create mode 100644 site/public/pattern-previews/state-machine.svg create mode 100644 site/public/pattern-previews/state.svg create mode 100644 site/public/pattern-previews/strategy.svg create mode 100644 site/public/pattern-previews/template-method.svg create mode 100644 site/public/pattern-previews/timeout-deadline-propagation.svg create mode 100644 site/public/pattern-previews/transactional-outbox.svg create mode 100644 site/public/pattern-previews/visitor.svg create mode 100644 site/scripts/generate-pattern-preview.mjs diff --git a/site/package-lock.json b/site/package-lock.json index e410e38..a80daa9 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -10,7 +10,9 @@ "dependencies": { "flexsearch": "^0.8.212", "gray-matter": "^4.0.3", + "highlight.js": "^11.11.1", "markdown-it": "^14.1.0", + "mermaid": "^11.6.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.3.0" @@ -41,6 +43,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -323,6 +338,51 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "license": "MIT" + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", + "license": "Apache-2.0" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", @@ -765,6 +825,23 @@ "node": ">=18" } }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -815,6 +892,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mermaid-js/parser": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.0.tgz", + "integrity": "sha512-vvK0Hi/VWndxoh03Mmz6wa1KDriSPjS2XMZL/1l19HFwygiObEEoEwSDxOqyLzzAI6J2PU3261JjTMTO7x+BPw==", + "license": "MIT", + "dependencies": { + "langium": "^4.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1268,6 +1354,259 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1275,6 +1614,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "24.12.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", @@ -1305,6 +1650,13 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@vitejs/plugin-react": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", @@ -1326,6 +1678,18 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -1504,6 +1868,32 @@ ], "license": "CC-BY-4.0" }, + "node_modules/chevrotain": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -1552,6 +1942,12 @@ "node": ">= 6" } }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1572,6 +1968,15 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1592,75 +1997,610 @@ "dev": true, "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, + "node_modules/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "cose-base": "^1.0.0" }, - "engines": { - "node": ">=6.0" + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", - "dev": true, - "license": "ISC" + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, "engines": { - "node": ">=0.12" + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": ">=12" } }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" }, "engines": { - "node": ">=18" + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz", + "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delaunator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dompurify": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", + "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", @@ -1878,6 +2818,12 @@ "node": ">=6.0" } }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "license": "MIT" + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1891,6 +2837,36 @@ "node": ">= 0.4" } }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2018,6 +2994,36 @@ "node": ">=6" } }, + "node_modules/katex": { + "version": "0.16.37", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.37.tgz", + "integrity": "sha512-TIGjO2cCGYono+uUzgkE7RFF329mLLWGuHUlSr6cwIVj9O8f0VQZ783rsanmJpFUo32vvtj7XT04NGRPh+SZFg==", + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2027,6 +3033,29 @@ "node": ">=0.10.0" } }, + "node_modules/langium": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "license": "MIT", + "dependencies": { + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "license": "MIT" + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -2056,6 +3085,12 @@ "uc.micro": "^2.0.0" } }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2089,6 +3124,18 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -2105,6 +3152,34 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.12.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.3.tgz", + "integrity": "sha512-wN5ZSgJQIC+CHJut9xaKWsknLxaFBwCPwPkGTSUYrTiHORWvpT8RxGk849HPnpUAQ+/9BPRqYb80jTpearrHzQ==", + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.1", + "@mermaid-js/parser": "^1.0.0", + "@types/d3": "^7.4.3", + "cytoscape": "^3.29.3", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.13", + "dayjs": "^1.11.18", + "dompurify": "^3.2.5", + "katex": "^0.16.22", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.2.1", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2119,6 +3194,18 @@ "node": ">=8.6" } }, + "node_modules/mlly": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2194,6 +3281,18 @@ "node": ">= 6" } }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "license": "MIT" + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "license": "MIT" + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2201,6 +3300,12 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2241,6 +3346,33 @@ "node": ">= 6" } }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/postcss": { "version": "8.5.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", @@ -2572,6 +3704,12 @@ "node": ">=0.10.0" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -2617,6 +3755,18 @@ "fsevents": "~2.3.2" } }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2641,6 +3791,18 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -2701,6 +3863,12 @@ "node": ">=0.10.0" } }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, "node_modules/sucrase": { "version": "3.35.1", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", @@ -2812,6 +3980,15 @@ "node": ">=0.8" } }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2873,6 +4050,15 @@ "node": ">=8.0" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -2900,6 +4086,12 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "license": "MIT" + }, "node_modules/undici-types": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", @@ -2945,6 +4137,19 @@ "dev": true, "license": "MIT" }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vite": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", @@ -3051,6 +4256,55 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/site/package.json b/site/package.json index fee67e0..a46add2 100644 --- a/site/package.json +++ b/site/package.json @@ -12,7 +12,9 @@ "dependencies": { "flexsearch": "^0.8.212", "gray-matter": "^4.0.3", + "highlight.js": "^11.11.1", "markdown-it": "^14.1.0", + "mermaid": "^11.6.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.3.0" diff --git a/site/public/pattern-previews/abstract-factory.svg b/site/public/pattern-previews/abstract-factory.svg new file mode 100644 index 0000000..c6658fc --- /dev/null +++ b/site/public/pattern-previews/abstract-factory.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Abstract Factory + creational + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/adapter.svg b/site/public/pattern-previews/adapter.svg new file mode 100644 index 0000000..b2b57dd --- /dev/null +++ b/site/public/pattern-previews/adapter.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Adapter + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/bridge.svg b/site/public/pattern-previews/bridge.svg new file mode 100644 index 0000000..95c11f6 --- /dev/null +++ b/site/public/pattern-previews/bridge.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Bridge + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/builder.svg b/site/public/pattern-previews/builder.svg new file mode 100644 index 0000000..0aa1934 --- /dev/null +++ b/site/public/pattern-previews/builder.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Builder + creational + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/bulkhead.svg b/site/public/pattern-previews/bulkhead.svg new file mode 100644 index 0000000..7d79762 --- /dev/null +++ b/site/public/pattern-previews/bulkhead.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Bulkhead + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/chain.svg b/site/public/pattern-previews/chain.svg new file mode 100644 index 0000000..78c1e08 --- /dev/null +++ b/site/public/pattern-previews/chain.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Chain of Responsibility + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/circuit-breaker.svg b/site/public/pattern-previews/circuit-breaker.svg new file mode 100644 index 0000000..1d850a2 --- /dev/null +++ b/site/public/pattern-previews/circuit-breaker.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Circuit Breaker + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/command.svg b/site/public/pattern-previews/command.svg new file mode 100644 index 0000000..3d4a512 --- /dev/null +++ b/site/public/pattern-previews/command.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Command + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/composite.svg b/site/public/pattern-previews/composite.svg new file mode 100644 index 0000000..55b9c0e --- /dev/null +++ b/site/public/pattern-previews/composite.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Composite + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/cqrs.svg b/site/public/pattern-previews/cqrs.svg new file mode 100644 index 0000000..8be9d06 --- /dev/null +++ b/site/public/pattern-previews/cqrs.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ENTERPRISE-INTEGRATION + CQRS Pattern (Command Query Responsibility Segregation) + enterprise-integration • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/decorator.svg b/site/public/pattern-previews/decorator.svg new file mode 100644 index 0000000..a84323b --- /dev/null +++ b/site/public/pattern-previews/decorator.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Decorator + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/double-checked-locking.svg b/site/public/pattern-previews/double-checked-locking.svg new file mode 100644 index 0000000..441182f --- /dev/null +++ b/site/public/pattern-previews/double-checked-locking.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Double-Checked Locking + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/facade.svg b/site/public/pattern-previews/facade.svg new file mode 100644 index 0000000..b1050d1 --- /dev/null +++ b/site/public/pattern-previews/facade.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Facade + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/factory-method.svg b/site/public/pattern-previews/factory-method.svg new file mode 100644 index 0000000..027f968 --- /dev/null +++ b/site/public/pattern-previews/factory-method.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Factory Method + creational + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/filter.svg b/site/public/pattern-previews/filter.svg new file mode 100644 index 0000000..130eee5 --- /dev/null +++ b/site/public/pattern-previews/filter.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + MISCELLANEOUS + Filter + miscellaneous • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/flyweight.svg b/site/public/pattern-previews/flyweight.svg new file mode 100644 index 0000000..f7ac897 --- /dev/null +++ b/site/public/pattern-previews/flyweight.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Flyweight + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/hedge-requests.svg b/site/public/pattern-previews/hedge-requests.svg new file mode 100644 index 0000000..3849a21 --- /dev/null +++ b/site/public/pattern-previews/hedge-requests.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Hedge Requests + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/idempotency-keys.svg b/site/public/pattern-previews/idempotency-keys.svg new file mode 100644 index 0000000..1a07672 --- /dev/null +++ b/site/public/pattern-previews/idempotency-keys.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Idempotency Keys + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/interpreter.svg b/site/public/pattern-previews/interpreter.svg new file mode 100644 index 0000000..789cb0b --- /dev/null +++ b/site/public/pattern-previews/interpreter.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Interpreter + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/iterator.svg b/site/public/pattern-previews/iterator.svg new file mode 100644 index 0000000..3db2d23 --- /dev/null +++ b/site/public/pattern-previews/iterator.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Iterator + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/lazy-sequence.svg b/site/public/pattern-previews/lazy-sequence.svg new file mode 100644 index 0000000..ef96e92 --- /dev/null +++ b/site/public/pattern-previews/lazy-sequence.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + MISCELLANEOUS + Lazy Sequence + miscellaneous • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/mediator.svg b/site/public/pattern-previews/mediator.svg new file mode 100644 index 0000000..6cc6a05 --- /dev/null +++ b/site/public/pattern-previews/mediator.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Mediator + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/memento.svg b/site/public/pattern-previews/memento.svg new file mode 100644 index 0000000..98ee6f4 --- /dev/null +++ b/site/public/pattern-previews/memento.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Memento + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/method-object.svg b/site/public/pattern-previews/method-object.svg new file mode 100644 index 0000000..613e7a8 --- /dev/null +++ b/site/public/pattern-previews/method-object.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + MISCELLANEOUS + Method Object + miscellaneous • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/model-view-presenter.svg b/site/public/pattern-previews/model-view-presenter.svg new file mode 100644 index 0000000..ef976df --- /dev/null +++ b/site/public/pattern-previews/model-view-presenter.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ARCHITECTURAL + Model-View-Presenter + architectural • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/nullobject.svg b/site/public/pattern-previews/nullobject.svg new file mode 100644 index 0000000..ef43dcc --- /dev/null +++ b/site/public/pattern-previews/nullobject.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Null Object + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/observer.svg b/site/public/pattern-previews/observer.svg new file mode 100644 index 0000000..30f3012 --- /dev/null +++ b/site/public/pattern-previews/observer.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Observer + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/pipes-and-filters.svg b/site/public/pattern-previews/pipes-and-filters.svg new file mode 100644 index 0000000..b1a99de --- /dev/null +++ b/site/public/pattern-previews/pipes-and-filters.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ENTERPRISE-INTEGRATION + Pipes and Filters + enterprise-integration • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/prototype.svg b/site/public/pattern-previews/prototype.svg new file mode 100644 index 0000000..ad5cd41 --- /dev/null +++ b/site/public/pattern-previews/prototype.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Prototype + creational + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/proxy.svg b/site/public/pattern-previews/proxy.svg new file mode 100644 index 0000000..b980a69 --- /dev/null +++ b/site/public/pattern-previews/proxy.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Proxy + structural + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/rate-limiter.svg b/site/public/pattern-previews/rate-limiter.svg new file mode 100644 index 0000000..4ac998c --- /dev/null +++ b/site/public/pattern-previews/rate-limiter.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Rate Limiter + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/retry-backoff.svg b/site/public/pattern-previews/retry-backoff.svg new file mode 100644 index 0000000..dfb57ac --- /dev/null +++ b/site/public/pattern-previews/retry-backoff.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Retry with Backoff + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/saga.svg b/site/public/pattern-previews/saga.svg new file mode 100644 index 0000000..27197e6 --- /dev/null +++ b/site/public/pattern-previews/saga.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ENTERPRISE-INTEGRATION + Saga + enterprise-integration • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/servant.svg b/site/public/pattern-previews/servant.svg new file mode 100644 index 0000000..3b0c41d --- /dev/null +++ b/site/public/pattern-previews/servant.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + MISCELLANEOUS + Servant + miscellaneous • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/service-locator.svg b/site/public/pattern-previews/service-locator.svg new file mode 100644 index 0000000..616487a --- /dev/null +++ b/site/public/pattern-previews/service-locator.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ARCHITECTURAL + Service Locator + architectural • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/singleton.svg b/site/public/pattern-previews/singleton.svg new file mode 100644 index 0000000..fd5a512 --- /dev/null +++ b/site/public/pattern-previews/singleton.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Singleton + creational + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/state-machine.svg b/site/public/pattern-previews/state-machine.svg new file mode 100644 index 0000000..317a16a --- /dev/null +++ b/site/public/pattern-previews/state-machine.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ARCHITECTURAL + State Machine + architectural • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/state.svg b/site/public/pattern-previews/state.svg new file mode 100644 index 0000000..75dcc17 --- /dev/null +++ b/site/public/pattern-previews/state.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + State + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/strategy.svg b/site/public/pattern-previews/strategy.svg new file mode 100644 index 0000000..d2b3131 --- /dev/null +++ b/site/public/pattern-previews/strategy.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Strategy + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/template-method.svg b/site/public/pattern-previews/template-method.svg new file mode 100644 index 0000000..766296c --- /dev/null +++ b/site/public/pattern-previews/template-method.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Template Method + behavioral + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/timeout-deadline-propagation.svg b/site/public/pattern-previews/timeout-deadline-propagation.svg new file mode 100644 index 0000000..d615087 --- /dev/null +++ b/site/public/pattern-previews/timeout-deadline-propagation.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + RELIABILITY + Timeout & Deadline Propagation + reliability • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/transactional-outbox.svg b/site/public/pattern-previews/transactional-outbox.svg new file mode 100644 index 0000000..5ff6f6f --- /dev/null +++ b/site/public/pattern-previews/transactional-outbox.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + ENTERPRISE-INTEGRATION + Transactional Outbox + enterprise-integration • overview + + + + + + + \ No newline at end of file diff --git a/site/public/pattern-previews/visitor.svg b/site/public/pattern-previews/visitor.svg new file mode 100644 index 0000000..b71649e --- /dev/null +++ b/site/public/pattern-previews/visitor.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + GOF + Visitor + behavioral + + + + + + + \ No newline at end of file diff --git a/site/scripts/build-pattern-index.mjs b/site/scripts/build-pattern-index.mjs index 5767077..4d471cc 100644 --- a/site/scripts/build-pattern-index.mjs +++ b/site/scripts/build-pattern-index.mjs @@ -1,6 +1,7 @@ import { promises as fs } from "node:fs"; import path from "node:path"; import { extractPatternMetadata } from "./extract-pattern-metadata.mjs"; +import { generatePatternPreview } from "./generate-pattern-preview.mjs"; const CATEGORY_FOLDERS = [ "gof-patterns", @@ -86,18 +87,29 @@ async function build() { const markdownSource = await fs.readFile(readmePath, "utf8"); const hasTests = await exists(path.join(patternPath, "src/test")); const demoCodePaths = await listDemoCodePaths(patternPath); - - patterns.push( - await extractPatternMetadata({ - categoryFolder, - folderName, - repoPath, - githubUrl: `https://github.com/SaumilP/design-patterns/tree/main/${repoPath}`, - markdownSource, - hasTests, - demoCodePaths, - }), - ); + const record = await extractPatternMetadata({ + categoryFolder, + folderName, + repoPath, + githubUrl: `https://github.com/SaumilP/design-patterns/tree/main/${repoPath}`, + markdownSource, + hasTests, + demoCodePaths, + }); + + const previewImage = await generatePatternPreview({ + siteRoot, + slug: record.slug, + name: record.name, + category: record.category, + subcategory: record.subcategory, + tags: record.tags, + }); + + record.previewImage = previewImage; + record.previewThumbnailImage = previewImage; + + patterns.push(record); } } diff --git a/site/scripts/extract-pattern-metadata.mjs b/site/scripts/extract-pattern-metadata.mjs index 37b11c6..63e62f8 100644 --- a/site/scripts/extract-pattern-metadata.mjs +++ b/site/scripts/extract-pattern-metadata.mjs @@ -1,5 +1,6 @@ import MarkdownIt from "markdown-it"; import matter from "gray-matter"; +import hljs from "highlight.js"; import { collectHeadings, getFirstParagraph, @@ -12,12 +13,38 @@ import { uniqueNormalized, } from "./markdown-utils.mjs"; +function escapeHtml(value) { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + const markdown = new MarkdownIt({ html: true, linkify: true, typographer: true, }); +markdown.renderer.rules.fence = (tokens, index) => { + const token = tokens[index]; + const language = (token.info || "").trim().split(/\s+/)[0]; + const code = token.content; + + if (language === "mermaid") { + return `
${escapeHtml(code)}
`; + } + + const validLanguage = language && hljs.getLanguage(language); + const highlighted = validLanguage + ? hljs.highlight(code, { language }).value + : hljs.highlightAuto(code).value; + const label = validLanguage ? language : "code"; + + return `
${escapeHtml(label)}
${highlighted}
`; +}; + const CATEGORY_LABELS = { gof: "GoF", architectural: "Architectural", diff --git a/site/scripts/generate-pattern-preview.mjs b/site/scripts/generate-pattern-preview.mjs new file mode 100644 index 0000000..4ed0cc9 --- /dev/null +++ b/site/scripts/generate-pattern-preview.mjs @@ -0,0 +1,131 @@ +import { promises as fs } from "node:fs"; +import path from "node:path"; + +const categoryPalettes = { + gof: { + start: "#ffb38a", + end: "#f59e7a", + stroke: "#7c2d12", + bg: "#fff1e8", + accent: "#fb923c", + }, + architectural: { + start: "#c4b5fd", + end: "#8b5cf6", + stroke: "#4c1d95", + bg: "#f5f3ff", + accent: "#7c3aed", + }, + "enterprise-integration": { + start: "#7dd3fc", + end: "#38bdf8", + stroke: "#0c4a6e", + bg: "#eff6ff", + accent: "#0284c7", + }, + reliability: { + start: "#fcd34d", + end: "#fb923c", + stroke: "#7c2d12", + bg: "#fff7ed", + accent: "#ea580c", + }, + miscellaneous: { + start: "#94a3b8", + end: "#64748b", + stroke: "#1e293b", + bg: "#f8fafc", + accent: "#475569", + }, +}; + +function seededValues(seed) { + let state = 0; + for (const char of seed) { + state = (state * 31 + char.charCodeAt(0)) >>> 0; + } + + return () => { + state = (1664525 * state + 1013904223) >>> 0; + return state / 4294967296; + }; +} + +function escapeHtml(value) { + return value + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +export async function generatePatternPreview({ + siteRoot, + slug, + name, + category, + subcategory, + tags, +}) { + const palette = categoryPalettes[category]; + const outputDir = path.join(siteRoot, "public", "pattern-previews"); + await fs.mkdir(outputDir, { recursive: true }); + + const rand = seededValues(slug); + const circles = Array.from({ length: 5 }, (_, index) => { + const cx = 160 + Math.round(rand() * 730); + const cy = 45 + Math.round(rand() * 170); + const radius = 18 + Math.round(rand() * 34); + const opacity = 0.12 + rand() * 0.12; + return ``; + }).join(""); + + const bars = Array.from({ length: 4 }, (_, index) => { + const x = 110 + index * 165; + const y = 146 + Math.round(rand() * 34); + const width = 110 + Math.round(rand() * 34); + return ``; + }).join(""); + + const title = escapeHtml(name); + const subtitle = escapeHtml(subcategory || tags.slice(0, 2).join(" • ") || "design pattern"); + + const svg = ` + + + + + + + + + + + + + + + + + + + ${circles} + + + ${escapeHtml(category.toUpperCase())} + ${title} + ${subtitle} + ${bars} + + + + + +`; + + const filename = `${slug}.svg`; + const outputPath = path.join(outputDir, filename); + await fs.writeFile(outputPath, svg, "utf8"); + + return `/pattern-previews/${filename}`; +} diff --git a/site/src/App.tsx b/site/src/App.tsx index be0ce34..458b55a 100644 --- a/site/src/App.tsx +++ b/site/src/App.tsx @@ -130,7 +130,7 @@ function HomeRoute(props: { patterns: PatternRecord[]; onOpenPalette: () => void ); } -function PatternRoute(props: { patterns: PatternRecord[]; relatedPatterns: RelatedPatternMap }) { +function PatternRoute(props: { patterns: PatternRecord[]; relatedPatterns: RelatedPatternMap; theme: "dark" | "light" }) { const { slug } = useParams(); const pattern = props.patterns.find((item) => item.slug === slug); if (!pattern) { @@ -139,7 +139,7 @@ function PatternRoute(props: { patterns: PatternRecord[]; relatedPatterns: Relat const related = (props.relatedPatterns[pattern.id] ?? []) .map((id) => props.patterns.find((candidate) => candidate.id === id)) .filter((item): item is PatternRecord => Boolean(item)); - return ; + return ; } export default function App() { @@ -147,8 +147,23 @@ export default function App() { const [relatedPatterns, setRelatedPatterns] = useState({}); const [isLoading, setIsLoading] = useState(true); const [paletteOpen, setPaletteOpen] = useState(false); + const [theme, setTheme] = useState<"dark" | "light">("dark"); const { recentSearches, remember } = useRecentSearches(); + useEffect(() => { + const stored = window.localStorage.getItem("pattern-theme"); + if (stored === "dark" || stored === "light") { + setTheme(stored); + } else if (window.matchMedia("(prefers-color-scheme: light)").matches) { + setTheme("light"); + } + }, []); + + useEffect(() => { + document.documentElement.dataset.theme = theme; + window.localStorage.setItem("pattern-theme", theme); + }, [theme]); + useEffect(() => { let active = true; @@ -190,7 +205,11 @@ export default function App() { }, []); return ( - setPaletteOpen(true)}> + setPaletteOpen(true)} + theme={theme} + onToggleTheme={() => setTheme((value) => (value === "dark" ? "light" : "dark"))} + > setPaletteOpen(false)} @@ -209,7 +228,7 @@ export default function App() { setPaletteOpen(true)} />} /> setPaletteOpen(true)} />} /> - } /> + } /> setPaletteOpen(true)} />} /> } /> } /> diff --git a/site/src/components/common/Button.tsx b/site/src/components/common/Button.tsx index eabf7d3..5aedff3 100644 --- a/site/src/components/common/Button.tsx +++ b/site/src/components/common/Button.tsx @@ -12,11 +12,11 @@ type Props = const variants = { primary: - "border border-cyan-400/30 bg-cyan-400/18 text-cyan-100 hover:border-cyan-300 hover:bg-cyan-400/28", + "border border-cyan-400/30 bg-[var(--button-primary-bg)] text-[var(--button-primary-text)] hover:border-cyan-300 hover:bg-[var(--button-primary-bg-hover)]", secondary: - "border border-white/14 bg-white/[0.04] text-slate-100 hover:border-white/28 hover:bg-white/[0.08]", + "border border-[color:var(--border-strong)] bg-[var(--panel-soft)] text-[var(--text-primary)] hover:bg-[var(--panel)]", ghost: - "border border-transparent bg-transparent text-slate-200 hover:border-white/14 hover:bg-white/[0.05]", + "border border-transparent bg-transparent text-[var(--text-secondary)] hover:border-[color:var(--border)] hover:bg-[var(--panel-soft)]", }; export function Button({ children, className = "", variant = "primary", ...props }: Props) { diff --git a/site/src/components/filters/CategoryFilterBar.tsx b/site/src/components/filters/CategoryFilterBar.tsx index fc80a64..a95fe31 100644 --- a/site/src/components/filters/CategoryFilterBar.tsx +++ b/site/src/components/filters/CategoryFilterBar.tsx @@ -15,7 +15,7 @@ export function CategoryFilterBar(props: { className={`rounded-full px-4 py-2 text-sm font-semibold transition ${ activeCategory === "all" ? "bg-cyan-400/18 text-cyan-100" - : "border border-white/10 bg-white/[0.04] text-slate-300 hover:border-white/20" + : "border border-[color:var(--border)] bg-[var(--panel-soft)] text-[var(--text-secondary)] hover:border-[color:var(--border-strong)]" }`} > All @@ -28,7 +28,7 @@ export function CategoryFilterBar(props: { className={`rounded-full px-4 py-2 text-sm font-semibold transition ${ activeCategory === category.id ? "bg-cyan-400/18 text-cyan-100" - : "border border-white/10 bg-white/[0.04] text-slate-300 hover:border-white/20" + : "border border-[color:var(--border)] bg-[var(--panel-soft)] text-[var(--text-secondary)] hover:border-[color:var(--border-strong)]" }`} > {category.label} diff --git a/site/src/components/layout/AppShell.tsx b/site/src/components/layout/AppShell.tsx index 83db59a..584a511 100644 --- a/site/src/components/layout/AppShell.tsx +++ b/site/src/components/layout/AppShell.tsx @@ -5,19 +5,21 @@ import { Header } from "./Header"; interface AppShellProps { children: ReactNode; onOpenSearch: () => void; + theme: "dark" | "light"; + onToggleTheme: () => void; } -export function AppShell({ children, onOpenSearch }: AppShellProps) { +export function AppShell({ children, onOpenSearch, theme, onToggleTheme }: AppShellProps) { return ( -
+
Skip to content -
-
+
+
{children}
diff --git a/site/src/components/layout/Footer.tsx b/site/src/components/layout/Footer.tsx index cc60798..027ac8e 100644 --- a/site/src/components/layout/Footer.tsx +++ b/site/src/components/layout/Footer.tsx @@ -3,11 +3,11 @@ import { Button } from "../common/Button"; export function Footer() { return ( -