#
tokens: 35645/50000 2/274 files (page 23/29)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 23 of 29. Use http://codebase.md/tosin2013/documcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .dockerignore
├── .eslintignore
├── .eslintrc.json
├── .github
│   ├── agents
│   │   ├── documcp-ast.md
│   │   ├── documcp-deploy.md
│   │   ├── documcp-memory.md
│   │   ├── documcp-test.md
│   │   └── documcp-tool.md
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── automated-changelog.md
│   │   ├── bug_report.md
│   │   ├── bug_report.yml
│   │   ├── documentation_issue.md
│   │   ├── feature_request.md
│   │   ├── feature_request.yml
│   │   ├── npm-publishing-fix.md
│   │   └── release_improvements.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── release-drafter.yml
│   └── workflows
│       ├── auto-merge.yml
│       ├── ci.yml
│       ├── codeql.yml
│       ├── dependency-review.yml
│       ├── deploy-docs.yml
│       ├── README.md
│       ├── release-drafter.yml
│       └── release.yml
├── .gitignore
├── .husky
│   ├── commit-msg
│   └── pre-commit
├── .linkcheck.config.json
├── .markdown-link-check.json
├── .nvmrc
├── .pre-commit-config.yaml
├── .versionrc.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── commitlint.config.js
├── CONTRIBUTING.md
├── docker-compose.docs.yml
├── Dockerfile.docs
├── docs
│   ├── .docusaurus
│   │   ├── docusaurus-plugin-content-docs
│   │   │   └── default
│   │   │       └── __mdx-loader-dependency.json
│   │   └── docusaurus-plugin-content-pages
│   │       └── default
│   │           └── __plugin.json
│   ├── adrs
│   │   ├── 001-mcp-server-architecture.md
│   │   ├── 002-repository-analysis-engine.md
│   │   ├── 003-static-site-generator-recommendation-engine.md
│   │   ├── 004-diataxis-framework-integration.md
│   │   ├── 005-github-pages-deployment-automation.md
│   │   ├── 006-mcp-tools-api-design.md
│   │   ├── 007-mcp-prompts-and-resources-integration.md
│   │   ├── 008-intelligent-content-population-engine.md
│   │   ├── 009-content-accuracy-validation-framework.md
│   │   ├── 010-mcp-resource-pattern-redesign.md
│   │   └── README.md
│   ├── api
│   │   ├── .nojekyll
│   │   ├── assets
│   │   │   ├── hierarchy.js
│   │   │   ├── highlight.css
│   │   │   ├── icons.js
│   │   │   ├── icons.svg
│   │   │   ├── main.js
│   │   │   ├── navigation.js
│   │   │   ├── search.js
│   │   │   └── style.css
│   │   ├── hierarchy.html
│   │   ├── index.html
│   │   ├── modules.html
│   │   └── variables
│   │       └── TOOLS.html
│   ├── assets
│   │   └── logo.svg
│   ├── development
│   │   └── MCP_INSPECTOR_TESTING.md
│   ├── docusaurus.config.js
│   ├── explanation
│   │   ├── architecture.md
│   │   └── index.md
│   ├── guides
│   │   ├── link-validation.md
│   │   ├── playwright-integration.md
│   │   └── playwright-testing-workflow.md
│   ├── how-to
│   │   ├── analytics-setup.md
│   │   ├── custom-domains.md
│   │   ├── documentation-freshness-tracking.md
│   │   ├── github-pages-deployment.md
│   │   ├── index.md
│   │   ├── local-testing.md
│   │   ├── performance-optimization.md
│   │   ├── prompting-guide.md
│   │   ├── repository-analysis.md
│   │   ├── seo-optimization.md
│   │   ├── site-monitoring.md
│   │   ├── troubleshooting.md
│   │   └── usage-examples.md
│   ├── index.md
│   ├── knowledge-graph.md
│   ├── package-lock.json
│   ├── package.json
│   ├── phase-2-intelligence.md
│   ├── reference
│   │   ├── api-overview.md
│   │   ├── cli.md
│   │   ├── configuration.md
│   │   ├── deploy-pages.md
│   │   ├── index.md
│   │   ├── mcp-tools.md
│   │   └── prompt-templates.md
│   ├── research
│   │   ├── cross-domain-integration
│   │   │   └── README.md
│   │   ├── domain-1-mcp-architecture
│   │   │   ├── index.md
│   │   │   └── mcp-performance-research.md
│   │   ├── domain-2-repository-analysis
│   │   │   └── README.md
│   │   ├── domain-3-ssg-recommendation
│   │   │   ├── index.md
│   │   │   └── ssg-performance-analysis.md
│   │   ├── domain-4-diataxis-integration
│   │   │   └── README.md
│   │   ├── domain-5-github-deployment
│   │   │   ├── github-pages-security-analysis.md
│   │   │   └── index.md
│   │   ├── domain-6-api-design
│   │   │   └── README.md
│   │   ├── README.md
│   │   ├── research-integration-summary-2025-01-14.md
│   │   ├── research-progress-template.md
│   │   └── research-questions-2025-01-14.md
│   ├── robots.txt
│   ├── sidebars.js
│   ├── sitemap.xml
│   ├── src
│   │   └── css
│   │       └── custom.css
│   └── tutorials
│       ├── development-setup.md
│       ├── environment-setup.md
│       ├── first-deployment.md
│       ├── getting-started.md
│       ├── index.md
│       ├── memory-workflows.md
│       └── user-onboarding.md
├── jest.config.js
├── LICENSE
├── Makefile
├── MCP_PHASE2_IMPLEMENTATION.md
├── mcp-config-example.json
├── mcp.json
├── package-lock.json
├── package.json
├── README.md
├── release.sh
├── scripts
│   └── check-package-structure.cjs
├── SECURITY.md
├── setup-precommit.sh
├── src
│   ├── benchmarks
│   │   └── performance.ts
│   ├── index.ts
│   ├── memory
│   │   ├── contextual-retrieval.ts
│   │   ├── deployment-analytics.ts
│   │   ├── enhanced-manager.ts
│   │   ├── export-import.ts
│   │   ├── freshness-kg-integration.ts
│   │   ├── index.ts
│   │   ├── integration.ts
│   │   ├── kg-code-integration.ts
│   │   ├── kg-health.ts
│   │   ├── kg-integration.ts
│   │   ├── kg-link-validator.ts
│   │   ├── kg-storage.ts
│   │   ├── knowledge-graph.ts
│   │   ├── learning.ts
│   │   ├── manager.ts
│   │   ├── multi-agent-sharing.ts
│   │   ├── pruning.ts
│   │   ├── schemas.ts
│   │   ├── storage.ts
│   │   ├── temporal-analysis.ts
│   │   ├── user-preferences.ts
│   │   └── visualization.ts
│   ├── prompts
│   │   └── technical-writer-prompts.ts
│   ├── scripts
│   │   └── benchmark.ts
│   ├── templates
│   │   └── playwright
│   │       ├── accessibility.spec.template.ts
│   │       ├── Dockerfile.template
│   │       ├── docs-e2e.workflow.template.yml
│   │       ├── link-validation.spec.template.ts
│   │       └── playwright.config.template.ts
│   ├── tools
│   │   ├── analyze-deployments.ts
│   │   ├── analyze-readme.ts
│   │   ├── analyze-repository.ts
│   │   ├── check-documentation-links.ts
│   │   ├── deploy-pages.ts
│   │   ├── detect-gaps.ts
│   │   ├── evaluate-readme-health.ts
│   │   ├── generate-config.ts
│   │   ├── generate-contextual-content.ts
│   │   ├── generate-llm-context.ts
│   │   ├── generate-readme-template.ts
│   │   ├── generate-technical-writer-prompts.ts
│   │   ├── kg-health-check.ts
│   │   ├── manage-preferences.ts
│   │   ├── manage-sitemap.ts
│   │   ├── optimize-readme.ts
│   │   ├── populate-content.ts
│   │   ├── readme-best-practices.ts
│   │   ├── recommend-ssg.ts
│   │   ├── setup-playwright-tests.ts
│   │   ├── setup-structure.ts
│   │   ├── sync-code-to-docs.ts
│   │   ├── test-local-deployment.ts
│   │   ├── track-documentation-freshness.ts
│   │   ├── update-existing-documentation.ts
│   │   ├── validate-content.ts
│   │   ├── validate-documentation-freshness.ts
│   │   ├── validate-readme-checklist.ts
│   │   └── verify-deployment.ts
│   ├── types
│   │   └── api.ts
│   ├── utils
│   │   ├── ast-analyzer.ts
│   │   ├── code-scanner.ts
│   │   ├── content-extractor.ts
│   │   ├── drift-detector.ts
│   │   ├── freshness-tracker.ts
│   │   ├── language-parsers-simple.ts
│   │   ├── permission-checker.ts
│   │   └── sitemap-generator.ts
│   └── workflows
│       └── documentation-workflow.ts
├── test-docs-local.sh
├── tests
│   ├── api
│   │   └── mcp-responses.test.ts
│   ├── benchmarks
│   │   └── performance.test.ts
│   ├── edge-cases
│   │   └── error-handling.test.ts
│   ├── functional
│   │   └── tools.test.ts
│   ├── integration
│   │   ├── kg-documentation-workflow.test.ts
│   │   ├── knowledge-graph-workflow.test.ts
│   │   ├── mcp-readme-tools.test.ts
│   │   ├── memory-mcp-tools.test.ts
│   │   ├── readme-technical-writer.test.ts
│   │   └── workflow.test.ts
│   ├── memory
│   │   ├── contextual-retrieval.test.ts
│   │   ├── enhanced-manager.test.ts
│   │   ├── export-import.test.ts
│   │   ├── freshness-kg-integration.test.ts
│   │   ├── kg-code-integration.test.ts
│   │   ├── kg-health.test.ts
│   │   ├── kg-link-validator.test.ts
│   │   ├── kg-storage-validation.test.ts
│   │   ├── kg-storage.test.ts
│   │   ├── knowledge-graph-enhanced.test.ts
│   │   ├── knowledge-graph.test.ts
│   │   ├── learning.test.ts
│   │   ├── manager-advanced.test.ts
│   │   ├── manager.test.ts
│   │   ├── mcp-resource-integration.test.ts
│   │   ├── mcp-tool-persistence.test.ts
│   │   ├── schemas.test.ts
│   │   ├── storage.test.ts
│   │   ├── temporal-analysis.test.ts
│   │   └── user-preferences.test.ts
│   ├── performance
│   │   ├── memory-load-testing.test.ts
│   │   └── memory-stress-testing.test.ts
│   ├── prompts
│   │   ├── guided-workflow-prompts.test.ts
│   │   └── technical-writer-prompts.test.ts
│   ├── server.test.ts
│   ├── setup.ts
│   ├── tools
│   │   ├── all-tools.test.ts
│   │   ├── analyze-coverage.test.ts
│   │   ├── analyze-deployments.test.ts
│   │   ├── analyze-readme.test.ts
│   │   ├── analyze-repository.test.ts
│   │   ├── check-documentation-links.test.ts
│   │   ├── deploy-pages-kg-retrieval.test.ts
│   │   ├── deploy-pages-tracking.test.ts
│   │   ├── deploy-pages.test.ts
│   │   ├── detect-gaps.test.ts
│   │   ├── evaluate-readme-health.test.ts
│   │   ├── generate-contextual-content.test.ts
│   │   ├── generate-llm-context.test.ts
│   │   ├── generate-readme-template.test.ts
│   │   ├── generate-technical-writer-prompts.test.ts
│   │   ├── kg-health-check.test.ts
│   │   ├── manage-sitemap.test.ts
│   │   ├── optimize-readme.test.ts
│   │   ├── readme-best-practices.test.ts
│   │   ├── recommend-ssg-historical.test.ts
│   │   ├── recommend-ssg-preferences.test.ts
│   │   ├── recommend-ssg.test.ts
│   │   ├── simple-coverage.test.ts
│   │   ├── sync-code-to-docs.test.ts
│   │   ├── test-local-deployment.test.ts
│   │   ├── tool-error-handling.test.ts
│   │   ├── track-documentation-freshness.test.ts
│   │   ├── validate-content.test.ts
│   │   ├── validate-documentation-freshness.test.ts
│   │   └── validate-readme-checklist.test.ts
│   ├── types
│   │   └── type-safety.test.ts
│   └── utils
│       ├── ast-analyzer.test.ts
│       ├── content-extractor.test.ts
│       ├── drift-detector.test.ts
│       ├── freshness-tracker.test.ts
│       └── sitemap-generator.test.ts
├── tsconfig.json
└── typedoc.json
```

# Files

--------------------------------------------------------------------------------
/tests/tools/sync-code-to-docs.test.ts:
--------------------------------------------------------------------------------

```typescript
   1 | /**
   2 |  * Sync Code to Docs Tool Tests (Phase 3)
   3 |  */
   4 | 
   5 | import { handleSyncCodeToDocs } from "../../src/tools/sync-code-to-docs.js";
   6 | import { promises as fs } from "fs";
   7 | import { tmpdir } from "os";
   8 | import { join } from "path";
   9 | import { mkdtemp, rm } from "fs/promises";
  10 | import { DriftDetector } from "../../src/utils/drift-detector.js";
  11 | 
  12 | describe("sync_code_to_docs tool", () => {
  13 |   let tempDir: string;
  14 |   let projectPath: string;
  15 |   let docsPath: string;
  16 | 
  17 |   beforeEach(async () => {
  18 |     tempDir = await mkdtemp(join(tmpdir(), "sync-test-"));
  19 |     projectPath = join(tempDir, "project");
  20 |     docsPath = join(tempDir, "docs");
  21 | 
  22 |     await fs.mkdir(join(projectPath, "src"), { recursive: true });
  23 |     await fs.mkdir(docsPath, { recursive: true });
  24 |   });
  25 | 
  26 |   afterEach(async () => {
  27 |     await rm(tempDir, { recursive: true, force: true });
  28 |   });
  29 | 
  30 |   describe("Detect Mode", () => {
  31 |     test("should detect drift without making changes", async () => {
  32 |       // Create source file
  33 |       const sourceCode = `
  34 | export function calculate(x: number): number {
  35 |   return x * 2;
  36 | }
  37 |       `.trim();
  38 | 
  39 |       await fs.writeFile(join(projectPath, "src", "calc.ts"), sourceCode);
  40 | 
  41 |       // Create documentation
  42 |       const docContent = `
  43 | # Calculator
  44 | 
  45 | ## calculate(x: number): number
  46 | 
  47 | Doubles the input.
  48 |       `.trim();
  49 | 
  50 |       await fs.writeFile(join(docsPath, "calc.md"), docContent);
  51 | 
  52 |       // Run in detect mode
  53 |       const result = await handleSyncCodeToDocs({
  54 |         projectPath,
  55 |         docsPath,
  56 |         mode: "detect",
  57 |         createSnapshot: true,
  58 |       });
  59 | 
  60 |       expect(result).toBeDefined();
  61 |       expect(result.content).toBeDefined();
  62 |       expect(result.content[0]).toBeDefined();
  63 | 
  64 |       const data = JSON.parse(result.content[0].text);
  65 |       expect(data.success).toBe(true);
  66 |       expect(data.data.mode).toBe("detect");
  67 | 
  68 |       // Verify no changes were made
  69 |       const docAfter = await fs.readFile(join(docsPath, "calc.md"), "utf-8");
  70 |       expect(docAfter).toBe(docContent);
  71 |     });
  72 | 
  73 |     test("should create baseline snapshot on first run", async () => {
  74 |       const sourceCode = `export function test(): void {}`;
  75 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
  76 | 
  77 |       const result = await handleSyncCodeToDocs({
  78 |         projectPath,
  79 |         docsPath,
  80 |         mode: "detect",
  81 |         createSnapshot: true,
  82 |       });
  83 | 
  84 |       expect(result).toBeDefined();
  85 | 
  86 |       const data = JSON.parse(result.content[0].text);
  87 |       expect(data.success).toBe(true);
  88 |       expect(data.data.snapshotId).toBeTruthy();
  89 | 
  90 |       // Check snapshot was created
  91 |       const snapshotDir = join(tempDir, "project", ".documcp", "snapshots");
  92 |       const files = await fs.readdir(snapshotDir);
  93 |       expect(files.length).toBeGreaterThan(0);
  94 |     });
  95 | 
  96 |     test("should report drift statistics", async () => {
  97 |       // Create initial snapshot
  98 |       const oldCode = `
  99 | export function oldFunction(): void {}
 100 |       `.trim();
 101 | 
 102 |       await fs.writeFile(join(projectPath, "src", "changes.ts"), oldCode);
 103 | 
 104 |       await handleSyncCodeToDocs({
 105 |         projectPath,
 106 |         docsPath,
 107 |         mode: "detect",
 108 |         createSnapshot: true,
 109 |       });
 110 | 
 111 |       // Make changes
 112 |       const newCode = `
 113 | export function newFunction(): void {}
 114 |       `.trim();
 115 | 
 116 |       await fs.writeFile(join(projectPath, "src", "changes.ts"), newCode);
 117 | 
 118 |       // Detect drift
 119 |       const result = await handleSyncCodeToDocs({
 120 |         projectPath,
 121 |         docsPath,
 122 |         mode: "detect",
 123 |         createSnapshot: true,
 124 |       });
 125 | 
 126 |       const data = JSON.parse(result.content[0].text);
 127 |       expect(data.success).toBe(true);
 128 |       expect(data.data.stats).toBeDefined();
 129 |       expect(data.data.stats.filesAnalyzed).toBeGreaterThanOrEqual(0);
 130 |     });
 131 |   });
 132 | 
 133 |   describe("Apply Mode", () => {
 134 |     test("should apply high-confidence changes automatically", async () => {
 135 |       // Create code with JSDoc
 136 |       const sourceCode = `
 137 | /**
 138 |  * Calculates the sum of two numbers
 139 |  * @param a First number
 140 |  * @param b Second number
 141 |  * @returns The sum
 142 |  */
 143 | export function add(a: number, b: number): number {
 144 |   return a + b;
 145 | }
 146 |       `.trim();
 147 | 
 148 |       await fs.writeFile(join(projectPath, "src", "math.ts"), sourceCode);
 149 | 
 150 |       // Create minimal documentation
 151 |       const docContent = `
 152 | # Math Module
 153 | 
 154 | Documentation needed.
 155 |       `.trim();
 156 | 
 157 |       await fs.writeFile(join(docsPath, "math.md"), docContent);
 158 | 
 159 |       // Create baseline
 160 |       await handleSyncCodeToDocs({
 161 |         projectPath,
 162 |         docsPath,
 163 |         mode: "detect",
 164 |         createSnapshot: true,
 165 |       });
 166 | 
 167 |       // Run in apply mode with high threshold
 168 |       const result = await handleSyncCodeToDocs({
 169 |         projectPath,
 170 |         docsPath,
 171 |         mode: "apply",
 172 |         autoApplyThreshold: 0.9,
 173 |         createSnapshot: true,
 174 |       });
 175 | 
 176 |       const data = JSON.parse(result.content[0].text);
 177 |       expect(data.success).toBe(true);
 178 |       expect(data.data.mode).toBe("apply");
 179 | 
 180 |       // Stats should show applied or pending changes
 181 |       const stats = data.data.stats;
 182 |       expect(
 183 |         stats.changesApplied + stats.changesPending,
 184 |       ).toBeGreaterThanOrEqual(0);
 185 |     });
 186 | 
 187 |     test("should respect confidence threshold", async () => {
 188 |       // Setup code and docs
 189 |       const sourceCode = `export function test(): void {}`;
 190 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 191 | 
 192 |       const docContent = `# Test`;
 193 |       await fs.writeFile(join(docsPath, "test.md"), docContent);
 194 | 
 195 |       // Create baseline
 196 |       await handleSyncCodeToDocs({
 197 |         projectPath,
 198 |         docsPath,
 199 |         mode: "detect",
 200 |       });
 201 | 
 202 |       // Apply with very high threshold (most changes won't meet it)
 203 |       const result = await handleSyncCodeToDocs({
 204 |         projectPath,
 205 |         docsPath,
 206 |         mode: "apply",
 207 |         autoApplyThreshold: 0.99,
 208 |       });
 209 | 
 210 |       const data = JSON.parse(result.content[0].text);
 211 |       expect(data.success).toBe(true);
 212 | 
 213 |       // With high threshold, most changes should be pending
 214 |       if (data.data.stats.driftsDetected > 0) {
 215 |         expect(data.data.pendingChanges.length).toBeGreaterThanOrEqual(0);
 216 |       }
 217 |     });
 218 | 
 219 |     test("should create snapshot before applying changes", async () => {
 220 |       const sourceCode = `export function test(): void {}`;
 221 |       await fs.writeFile(
 222 |         join(projectPath, "src", "snapshot-test.ts"),
 223 |         sourceCode,
 224 |       );
 225 | 
 226 |       await handleSyncCodeToDocs({
 227 |         projectPath,
 228 |         docsPath,
 229 |         mode: "apply",
 230 |         createSnapshot: true,
 231 |       });
 232 | 
 233 |       // Verify snapshot exists
 234 |       const snapshotDir = join(projectPath, ".documcp", "snapshots");
 235 |       const files = await fs.readdir(snapshotDir);
 236 |       expect(files.length).toBeGreaterThan(0);
 237 |     });
 238 |   });
 239 | 
 240 |   describe("Auto Mode", () => {
 241 |     test("should apply all changes in auto mode", async () => {
 242 |       const sourceCode = `
 243 | export function autoFunction(param: string): string {
 244 |   return param.toUpperCase();
 245 | }
 246 |       `.trim();
 247 | 
 248 |       await fs.writeFile(join(projectPath, "src", "auto.ts"), sourceCode);
 249 | 
 250 |       const result = await handleSyncCodeToDocs({
 251 |         projectPath,
 252 |         docsPath,
 253 |         mode: "auto",
 254 |         createSnapshot: true,
 255 |       });
 256 | 
 257 |       const data = JSON.parse(result.content[0].text);
 258 |       expect(data.success).toBe(true);
 259 |       expect(data.data.mode).toBe("auto");
 260 |     });
 261 |   });
 262 | 
 263 |   describe("Error Handling", () => {
 264 |     test("should handle invalid project path", async () => {
 265 |       const result = await handleSyncCodeToDocs({
 266 |         projectPath: "/nonexistent/path",
 267 |         docsPath,
 268 |         mode: "detect",
 269 |       });
 270 | 
 271 |       expect(result).toBeDefined();
 272 |       expect(result.content).toBeDefined();
 273 | 
 274 |       const data = JSON.parse(result.content[0].text);
 275 |       // Should either fail gracefully or handle missing path
 276 |       expect(data).toBeDefined();
 277 |     });
 278 | 
 279 |     test("should handle invalid docs path", async () => {
 280 |       const sourceCode = `export function test(): void {}`;
 281 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 282 | 
 283 |       const result = await handleSyncCodeToDocs({
 284 |         projectPath,
 285 |         docsPath: "/nonexistent/docs",
 286 |         mode: "detect",
 287 |       });
 288 | 
 289 |       expect(result).toBeDefined();
 290 |       const data = JSON.parse(result.content[0].text);
 291 |       expect(data).toBeDefined();
 292 |     });
 293 | 
 294 |     test("should handle empty project", async () => {
 295 |       // Empty project directory
 296 |       const result = await handleSyncCodeToDocs({
 297 |         projectPath,
 298 |         docsPath,
 299 |         mode: "detect",
 300 |       });
 301 | 
 302 |       expect(result).toBeDefined();
 303 |       const data = JSON.parse(result.content[0].text);
 304 |       expect(data.success).toBe(true);
 305 |       expect(data.data.stats.filesAnalyzed).toBe(0);
 306 |     });
 307 |   });
 308 | 
 309 |   describe("Recommendations and Next Steps", () => {
 310 |     test("should provide recommendations based on results", async () => {
 311 |       const sourceCode = `
 312 | export function critical(param: number): void {}
 313 |       `.trim();
 314 | 
 315 |       await fs.writeFile(join(projectPath, "src", "critical.ts"), sourceCode);
 316 | 
 317 |       // Create baseline
 318 |       await handleSyncCodeToDocs({
 319 |         projectPath,
 320 |         docsPath,
 321 |         mode: "detect",
 322 |       });
 323 | 
 324 |       // Make breaking change
 325 |       const newCode = `
 326 | export function critical(param: string, extra: boolean): void {}
 327 |       `.trim();
 328 | 
 329 |       await fs.writeFile(join(projectPath, "src", "critical.ts"), newCode);
 330 | 
 331 |       // Detect changes
 332 |       const result = await handleSyncCodeToDocs({
 333 |         projectPath,
 334 |         docsPath,
 335 |         mode: "detect",
 336 |       });
 337 | 
 338 |       const data = JSON.parse(result.content[0].text);
 339 |       expect(data.success).toBe(true);
 340 |       expect(data.recommendations).toBeDefined();
 341 |       expect(Array.isArray(data.recommendations)).toBe(true);
 342 |     });
 343 | 
 344 |     test("should provide next steps", async () => {
 345 |       const result = await handleSyncCodeToDocs({
 346 |         projectPath,
 347 |         docsPath,
 348 |         mode: "detect",
 349 |       });
 350 | 
 351 |       const data = JSON.parse(result.content[0].text);
 352 |       expect(data.success).toBe(true);
 353 |       expect(data.nextSteps).toBeDefined();
 354 |       expect(Array.isArray(data.nextSteps)).toBe(true);
 355 |     });
 356 |   });
 357 | 
 358 |   describe("Integration with Knowledge Graph", () => {
 359 |     test("should store sync events", async () => {
 360 |       const sourceCode = `export function kgTest(): void {}`;
 361 |       await fs.writeFile(join(projectPath, "src", "kg-test.ts"), sourceCode);
 362 | 
 363 |       const result = await handleSyncCodeToDocs({
 364 |         projectPath,
 365 |         docsPath,
 366 |         mode: "detect",
 367 |       });
 368 | 
 369 |       const data = JSON.parse(result.content[0].text);
 370 |       expect(data.success).toBe(true);
 371 | 
 372 |       // Sync event should be created (even if storage fails, shouldn't error)
 373 |       expect(data.data).toBeDefined();
 374 |     });
 375 |   });
 376 | 
 377 |   describe("Preview Mode", () => {
 378 |     test("should show changes in preview mode without applying", async () => {
 379 |       const sourceCode = `
 380 | export function previewFunc(x: number): number {
 381 |   return x * 3;
 382 | }
 383 |       `.trim();
 384 | 
 385 |       await fs.writeFile(join(projectPath, "src", "preview.ts"), sourceCode);
 386 | 
 387 |       const docContent = `
 388 | # Preview
 389 | 
 390 | Old documentation.
 391 |       `.trim();
 392 | 
 393 |       await fs.writeFile(join(docsPath, "preview.md"), docContent);
 394 | 
 395 |       // Create baseline
 396 |       await handleSyncCodeToDocs({
 397 |         projectPath,
 398 |         docsPath,
 399 |         mode: "detect",
 400 |       });
 401 | 
 402 |       // Change code
 403 |       const newCode = `
 404 | export function previewFunc(x: number, y: number): number {
 405 |   return x * y;
 406 | }
 407 |       `.trim();
 408 | 
 409 |       await fs.writeFile(join(projectPath, "src", "preview.ts"), newCode);
 410 | 
 411 |       // Preview changes
 412 |       const result = await handleSyncCodeToDocs({
 413 |         projectPath,
 414 |         docsPath,
 415 |         mode: "preview",
 416 |       });
 417 | 
 418 |       const data = JSON.parse(result.content[0].text);
 419 |       expect(data.success).toBe(true);
 420 |       expect(data.data.mode).toBe("preview");
 421 | 
 422 |       // Verify documentation wasn't changed
 423 |       const docAfter = await fs.readFile(join(docsPath, "preview.md"), "utf-8");
 424 |       expect(docAfter).toBe(docContent);
 425 |     });
 426 |   });
 427 | 
 428 |   describe("Documentation Change Application", () => {
 429 |     test("should apply changes when low-confidence changes exist in auto mode", async () => {
 430 |       // Create a source file with documentation
 431 |       const sourceCode = `
 432 | /**
 433 |  * Multiplies two numbers together
 434 |  * @param x First number
 435 |  * @param y Second number
 436 |  */
 437 | export function multiply(x: number, y: number): number {
 438 |   return x * y;
 439 | }
 440 |       `.trim();
 441 | 
 442 |       await fs.writeFile(join(projectPath, "src", "math.ts"), sourceCode);
 443 | 
 444 |       // Create outdated documentation
 445 |       const docContent = `
 446 | # Math Module
 447 | 
 448 | ## multiply
 449 | 
 450 | Adds two numbers.
 451 |       `.trim();
 452 | 
 453 |       await fs.writeFile(join(docsPath, "math.md"), docContent);
 454 | 
 455 |       // Create baseline
 456 |       await handleSyncCodeToDocs({
 457 |         projectPath,
 458 |         docsPath,
 459 |         mode: "detect",
 460 |       });
 461 | 
 462 |       // Run in auto mode (applies all changes)
 463 |       const result = await handleSyncCodeToDocs({
 464 |         projectPath,
 465 |         docsPath,
 466 |         mode: "auto",
 467 |       });
 468 | 
 469 |       const data = JSON.parse(result.content[0].text);
 470 |       expect(data.success).toBe(true);
 471 |       expect(data.data.mode).toBe("auto");
 472 |     });
 473 | 
 474 |     test("should handle apply errors gracefully", async () => {
 475 |       // Create source file
 476 |       const sourceCode = `export function testFunc(): void {}`;
 477 |       await fs.writeFile(join(projectPath, "src", "test.ts"), sourceCode);
 478 | 
 479 |       // Create documentation in a read-only parent directory would fail
 480 |       // But for this test, we'll just verify the error handling path exists
 481 |       const docContent = `# Test`;
 482 |       await fs.writeFile(join(docsPath, "test.md"), docContent);
 483 | 
 484 |       // Create baseline
 485 |       await handleSyncCodeToDocs({
 486 |         projectPath,
 487 |         docsPath,
 488 |         mode: "detect",
 489 |       });
 490 | 
 491 |       // Modify code
 492 |       const newCode = `export function testFunc(param: string): void {}`;
 493 |       await fs.writeFile(join(projectPath, "src", "test.ts"), newCode);
 494 | 
 495 |       // Try to apply changes
 496 |       const result = await handleSyncCodeToDocs({
 497 |         projectPath,
 498 |         docsPath,
 499 |         mode: "apply",
 500 |         autoApplyThreshold: 0.0, // Very low threshold
 501 |       });
 502 | 
 503 |       // Should complete without crashing
 504 |       expect(result).toBeDefined();
 505 |       const data = JSON.parse(result.content[0].text);
 506 |       expect(data.success).toBe(true);
 507 |     });
 508 |   });
 509 | 
 510 |   describe("Recommendation Edge Cases", () => {
 511 |     test("should recommend review for breaking changes", async () => {
 512 |       // Create initial code
 513 |       const oldCode = `
 514 | export function oldApi(x: number): string {
 515 |   return x.toString();
 516 | }
 517 |       `.trim();
 518 | 
 519 |       await fs.writeFile(join(projectPath, "src", "api.ts"), oldCode);
 520 | 
 521 |       // Create baseline
 522 |       await handleSyncCodeToDocs({
 523 |         projectPath,
 524 |         docsPath,
 525 |         mode: "detect",
 526 |       });
 527 | 
 528 |       // Make breaking change
 529 |       const newCode = `
 530 | export function newApi(x: number, y: string): boolean {
 531 |   return x > 0;
 532 | }
 533 |       `.trim();
 534 | 
 535 |       await fs.writeFile(join(projectPath, "src", "api.ts"), newCode);
 536 | 
 537 |       // Detect changes
 538 |       const result = await handleSyncCodeToDocs({
 539 |         projectPath,
 540 |         docsPath,
 541 |         mode: "detect",
 542 |       });
 543 | 
 544 |       const data = JSON.parse(result.content[0].text);
 545 |       expect(data.success).toBe(true);
 546 | 
 547 |       // Should have recommendations
 548 |       expect(data.recommendations).toBeDefined();
 549 |       expect(Array.isArray(data.recommendations)).toBe(true);
 550 |     });
 551 | 
 552 |     test("should show info when no drift detected", async () => {
 553 |       // Create code
 554 |       const sourceCode = `export function stable(): void {}`;
 555 |       await fs.writeFile(join(projectPath, "src", "stable.ts"), sourceCode);
 556 | 
 557 |       // Create baseline
 558 |       await handleSyncCodeToDocs({
 559 |         projectPath,
 560 |         docsPath,
 561 |         mode: "detect",
 562 |       });
 563 | 
 564 |       // Run again without changes
 565 |       const result = await handleSyncCodeToDocs({
 566 |         projectPath,
 567 |         docsPath,
 568 |         mode: "detect",
 569 |       });
 570 | 
 571 |       const data = JSON.parse(result.content[0].text);
 572 |       expect(data.success).toBe(true);
 573 |       expect(data.recommendations).toBeDefined();
 574 | 
 575 |       // Should have "No Drift Detected" recommendation
 576 |       const noDriftRec = data.recommendations.find(
 577 |         (r: any) => r.title?.includes("No Drift"),
 578 |       );
 579 |       expect(noDriftRec).toBeDefined();
 580 |     });
 581 | 
 582 |     test("should recommend validation after applying changes", async () => {
 583 |       const sourceCode = `
 584 | /**
 585 |  * Test function
 586 |  */
 587 | export function test(): void {}
 588 |       `.trim();
 589 | 
 590 |       await fs.writeFile(join(projectPath, "src", "validated.ts"), sourceCode);
 591 | 
 592 |       // Create baseline
 593 |       await handleSyncCodeToDocs({
 594 |         projectPath,
 595 |         docsPath,
 596 |         mode: "detect",
 597 |       });
 598 | 
 599 |       // Modify code
 600 |       const newCode = `
 601 | /**
 602 |  * Modified test function
 603 |  */
 604 | export function test(param: string): void {}
 605 |       `.trim();
 606 | 
 607 |       await fs.writeFile(join(projectPath, "src", "validated.ts"), newCode);
 608 | 
 609 |       // Apply changes
 610 |       const result = await handleSyncCodeToDocs({
 611 |         projectPath,
 612 |         docsPath,
 613 |         mode: "auto",
 614 |       });
 615 | 
 616 |       const data = JSON.parse(result.content[0].text);
 617 |       expect(data.success).toBe(true);
 618 | 
 619 |       // Should have next steps
 620 |       expect(data.nextSteps).toBeDefined();
 621 |       expect(Array.isArray(data.nextSteps)).toBe(true);
 622 |     });
 623 |   });
 624 | 
 625 |   describe("Next Steps Generation", () => {
 626 |     test("should suggest apply mode when in detect mode with pending changes", async () => {
 627 |       const sourceCode = `export function needsSync(): void {}`;
 628 |       await fs.writeFile(join(projectPath, "src", "sync.ts"), sourceCode);
 629 | 
 630 |       // Create baseline
 631 |       await handleSyncCodeToDocs({
 632 |         projectPath,
 633 |         docsPath,
 634 |         mode: "detect",
 635 |       });
 636 | 
 637 |       // Change code
 638 |       const newCode = `export function needsSync(param: number): void {}`;
 639 |       await fs.writeFile(join(projectPath, "src", "sync.ts"), newCode);
 640 | 
 641 |       // Detect in detect mode
 642 |       const result = await handleSyncCodeToDocs({
 643 |         projectPath,
 644 |         docsPath,
 645 |         mode: "detect",
 646 |       });
 647 | 
 648 |       const data = JSON.parse(result.content[0].text);
 649 |       expect(data.success).toBe(true);
 650 |       expect(data.nextSteps).toBeDefined();
 651 | 
 652 |       // If there are pending changes, should suggest apply mode
 653 |       if (data.data.pendingChanges?.length > 0) {
 654 |         const applyStep = data.nextSteps.find(
 655 |           (s: any) => s.action?.includes("Apply"),
 656 |         );
 657 |         expect(applyStep).toBeDefined();
 658 |       }
 659 |     });
 660 | 
 661 |     test("should suggest review for pending manual changes", async () => {
 662 |       const sourceCode = `export function complex(): void {}`;
 663 |       await fs.writeFile(join(projectPath, "src", "complex.ts"), sourceCode);
 664 | 
 665 |       // Create baseline
 666 |       await handleSyncCodeToDocs({
 667 |         projectPath,
 668 |         docsPath,
 669 |         mode: "detect",
 670 |       });
 671 | 
 672 |       // Change code
 673 |       const newCode = `export function complex(a: number, b: string): boolean { return true; }`;
 674 |       await fs.writeFile(join(projectPath, "src", "complex.ts"), newCode);
 675 | 
 676 |       // Detect with very high threshold (forces manual review)
 677 |       const result = await handleSyncCodeToDocs({
 678 |         projectPath,
 679 |         docsPath,
 680 |         mode: "apply",
 681 |         autoApplyThreshold: 0.99,
 682 |       });
 683 | 
 684 |       const data = JSON.parse(result.content[0].text);
 685 |       expect(data.success).toBe(true);
 686 |       expect(data.nextSteps).toBeDefined();
 687 |     });
 688 |   });
 689 | 
 690 |   describe("Snapshot Management", () => {
 691 |     test("should not create snapshot when createSnapshot is false in detect mode", async () => {
 692 |       const sourceCode = `export function noSnapshot(): void {}`;
 693 |       await fs.writeFile(join(projectPath, "src", "nosnapshot.ts"), sourceCode);
 694 | 
 695 |       await handleSyncCodeToDocs({
 696 |         projectPath,
 697 |         docsPath,
 698 |         mode: "detect",
 699 |         createSnapshot: false,
 700 |       });
 701 | 
 702 |       // Should still work even without snapshot
 703 |       const result = await handleSyncCodeToDocs({
 704 |         projectPath,
 705 |         docsPath,
 706 |         mode: "detect",
 707 |         createSnapshot: false,
 708 |       });
 709 | 
 710 |       const data = JSON.parse(result.content[0].text);
 711 |       expect(data.success).toBe(true);
 712 |     });
 713 |   });
 714 | 
 715 |   describe("Error Path Coverage", () => {
 716 |     test("should handle KG storage failures gracefully", async () => {
 717 |       const sourceCode = `export function kgError(): void {}`;
 718 |       await fs.writeFile(join(projectPath, "src", "kg-error.ts"), sourceCode);
 719 | 
 720 |       // The tool should complete even if KG storage fails
 721 |       const result = await handleSyncCodeToDocs({
 722 |         projectPath,
 723 |         docsPath,
 724 |         mode: "detect",
 725 |       });
 726 | 
 727 |       const data = JSON.parse(result.content[0].text);
 728 |       expect(data.success).toBe(true);
 729 |     });
 730 | 
 731 |     test("should handle zero drift detections", async () => {
 732 |       const sourceCode = `export function stable(): void {}`;
 733 |       await fs.writeFile(join(projectPath, "src", "stable.ts"), sourceCode);
 734 | 
 735 |       // Create baseline
 736 |       await handleSyncCodeToDocs({
 737 |         projectPath,
 738 |         docsPath,
 739 |         mode: "detect",
 740 |       });
 741 | 
 742 |       // Run again with no changes
 743 |       const result = await handleSyncCodeToDocs({
 744 |         projectPath,
 745 |         docsPath,
 746 |         mode: "detect",
 747 |       });
 748 | 
 749 |       const data = JSON.parse(result.content[0].text);
 750 |       expect(data.success).toBe(true);
 751 |       expect(data.data.stats.driftsDetected).toBe(0);
 752 |     });
 753 | 
 754 |     test("should handle files with no drift suggestions", async () => {
 755 |       const sourceCode = `export function noDrift(): void {}`;
 756 |       await fs.writeFile(join(projectPath, "src", "nodrift.ts"), sourceCode);
 757 | 
 758 |       const result = await handleSyncCodeToDocs({
 759 |         projectPath,
 760 |         docsPath,
 761 |         mode: "apply",
 762 |         autoApplyThreshold: 0.5,
 763 |       });
 764 | 
 765 |       const data = JSON.parse(result.content[0].text);
 766 |       expect(data.success).toBe(true);
 767 |       // Should handle case with no drift gracefully
 768 |       expect(data.data.appliedChanges).toBeDefined();
 769 |       expect(data.data.pendingChanges).toBeDefined();
 770 |     });
 771 | 
 772 |     test("should handle recommendations with zero breaking changes", async () => {
 773 |       const sourceCode = `export function minor(): void {}`;
 774 |       await fs.writeFile(join(projectPath, "src", "minor.ts"), sourceCode);
 775 | 
 776 |       const result = await handleSyncCodeToDocs({
 777 |         projectPath,
 778 |         docsPath,
 779 |         mode: "detect",
 780 |       });
 781 | 
 782 |       const data = JSON.parse(result.content[0].text);
 783 |       expect(data.success).toBe(true);
 784 |       // Should not have critical recommendations for no breaking changes
 785 |       const criticalRecs = data.recommendations?.filter(
 786 |         (r: any) => r.type === "critical",
 787 |       );
 788 |       expect(criticalRecs || []).toHaveLength(0);
 789 |     });
 790 | 
 791 |     test("should handle pending changes without manual review", async () => {
 792 |       const sourceCode = `export function autoApply(): void {}`;
 793 |       await fs.writeFile(join(projectPath, "src", "autoapply.ts"), sourceCode);
 794 | 
 795 |       // Create baseline
 796 |       await handleSyncCodeToDocs({
 797 |         projectPath,
 798 |         docsPath,
 799 |         mode: "detect",
 800 |       });
 801 | 
 802 |       // Modify
 803 |       const newCode = `export function autoApply(x: number): number { return x; }`;
 804 |       await fs.writeFile(join(projectPath, "src", "autoapply.ts"), newCode);
 805 | 
 806 |       const result = await handleSyncCodeToDocs({
 807 |         projectPath,
 808 |         docsPath,
 809 |         mode: "auto", // Auto applies all
 810 |       });
 811 | 
 812 |       const data = JSON.parse(result.content[0].text);
 813 |       expect(data.success).toBe(true);
 814 |     });
 815 | 
 816 |     test("should handle next steps when no breaking changes exist", async () => {
 817 |       const sourceCode = `export function noBreaking(): void {}`;
 818 |       await fs.writeFile(join(projectPath, "src", "nobreaking.ts"), sourceCode);
 819 | 
 820 |       const result = await handleSyncCodeToDocs({
 821 |         projectPath,
 822 |         docsPath,
 823 |         mode: "detect",
 824 |       });
 825 | 
 826 |       const data = JSON.parse(result.content[0].text);
 827 |       expect(data.success).toBe(true);
 828 |       // Should not suggest reviewing breaking changes when there are none
 829 |       const breakingStep = data.nextSteps?.find(
 830 |         (s: any) => s.action?.toLowerCase().includes("breaking"),
 831 |       );
 832 |       expect(breakingStep).toBeUndefined();
 833 |     });
 834 | 
 835 |     test("should handle next steps when no changes were applied", async () => {
 836 |       const sourceCode = `export function noApplied(): void {}`;
 837 |       await fs.writeFile(join(projectPath, "src", "noapplied.ts"), sourceCode);
 838 | 
 839 |       const result = await handleSyncCodeToDocs({
 840 |         projectPath,
 841 |         docsPath,
 842 |         mode: "detect", // Detect mode doesn't apply
 843 |       });
 844 | 
 845 |       const data = JSON.parse(result.content[0].text);
 846 |       expect(data.success).toBe(true);
 847 |       expect(data.data.appliedChanges).toHaveLength(0);
 848 |     });
 849 | 
 850 |     test("should handle next steps when no pending changes require review", async () => {
 851 |       const sourceCode = `export function noPending(): void {}`;
 852 |       await fs.writeFile(join(projectPath, "src", "nopending.ts"), sourceCode);
 853 | 
 854 |       const result = await handleSyncCodeToDocs({
 855 |         projectPath,
 856 |         docsPath,
 857 |         mode: "auto", // Auto applies everything
 858 |       });
 859 | 
 860 |       const data = JSON.parse(result.content[0].text);
 861 |       expect(data.success).toBe(true);
 862 |     });
 863 | 
 864 |     test("should handle apply mode with suggestions below threshold", async () => {
 865 |       const sourceCode = `export function lowConfidence(): void {}`;
 866 |       await fs.writeFile(
 867 |         join(projectPath, "src", "lowconfidence.ts"),
 868 |         sourceCode,
 869 |       );
 870 | 
 871 |       // Create baseline
 872 |       await handleSyncCodeToDocs({
 873 |         projectPath,
 874 |         docsPath,
 875 |         mode: "detect",
 876 |       });
 877 | 
 878 |       // Modify
 879 |       const newCode = `export function lowConfidence(param: string): void {}`;
 880 |       await fs.writeFile(join(projectPath, "src", "lowconfidence.ts"), newCode);
 881 | 
 882 |       // Very high threshold - suggestions won't meet it
 883 |       const result = await handleSyncCodeToDocs({
 884 |         projectPath,
 885 |         docsPath,
 886 |         mode: "apply",
 887 |         autoApplyThreshold: 1.0,
 888 |       });
 889 | 
 890 |       const data = JSON.parse(result.content[0].text);
 891 |       expect(data.success).toBe(true);
 892 |     });
 893 | 
 894 |     test("should handle context parameter with info logging", async () => {
 895 |       const sourceCode = `export function withContext(): void {}`;
 896 |       await fs.writeFile(join(projectPath, "src", "context.ts"), sourceCode);
 897 | 
 898 |       const mockContext = {
 899 |         info: jest.fn(),
 900 |         warn: jest.fn(),
 901 |       };
 902 | 
 903 |       const result = await handleSyncCodeToDocs(
 904 |         {
 905 |           projectPath,
 906 |           docsPath,
 907 |           mode: "detect",
 908 |         },
 909 |         mockContext,
 910 |       );
 911 | 
 912 |       const data = JSON.parse(result.content[0].text);
 913 |       expect(data.success).toBe(true);
 914 |       // Context info should have been called
 915 |       expect(mockContext.info).toHaveBeenCalled();
 916 |     });
 917 | 
 918 |     test("should handle snapshot creation in non-detect modes", async () => {
 919 |       const sourceCode = `export function modeSnapshot(): void {}`;
 920 |       await fs.writeFile(
 921 |         join(projectPath, "src", "modesnapshot.ts"),
 922 |         sourceCode,
 923 |       );
 924 | 
 925 |       // Apply mode should create snapshot even if createSnapshot not specified
 926 |       const result = await handleSyncCodeToDocs({
 927 |         projectPath,
 928 |         docsPath,
 929 |         mode: "apply",
 930 |         createSnapshot: false, // But mode !== "detect" overrides this
 931 |       });
 932 | 
 933 |       const data = JSON.parse(result.content[0].text);
 934 |       expect(data.success).toBe(true);
 935 |     });
 936 |   });
 937 | 
 938 |   describe("Mocked Drift Detector Tests", () => {
 939 |     let mockDetector: jest.Mocked<DriftDetector>;
 940 | 
 941 |     beforeEach(() => {
 942 |       // Create a real detector instance but spy on its methods
 943 |       mockDetector = new DriftDetector(
 944 |         projectPath,
 945 |       ) as jest.Mocked<DriftDetector>;
 946 |     });
 947 | 
 948 |     test("should apply high-confidence suggestions automatically", async () => {
 949 |       // Create real documentation file
 950 |       const docPath = join(docsPath, "api.md");
 951 |       const originalDoc = `# API
 952 | 
 953 | ## oldFunction
 954 | 
 955 | This is outdated.`;
 956 |       await fs.writeFile(docPath, originalDoc);
 957 | 
 958 |       // Mock drift detector to return suggestions
 959 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
 960 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
 961 |         timestamp: "2025-01-01T00:00:00.000Z",
 962 |         projectPath,
 963 |         files: new Map([
 964 |           [
 965 |             "src/api.ts",
 966 |             {
 967 |               filePath: "src/api.ts",
 968 |               language: "typescript",
 969 |               functions: [],
 970 |               classes: [],
 971 |               interfaces: [],
 972 |               types: [],
 973 |               imports: [],
 974 |               exports: [],
 975 |               contentHash: "abc123",
 976 |               lastModified: "2025-01-01T00:00:00.000Z",
 977 |               linesOfCode: 10,
 978 |               complexity: 1,
 979 |             },
 980 |           ],
 981 |         ]),
 982 |         documentation: new Map(),
 983 |       });
 984 | 
 985 |       jest
 986 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
 987 |         .mockResolvedValue({
 988 |           timestamp: "2025-01-01T00:00:00.000Z",
 989 |           projectPath,
 990 |           files: new Map(),
 991 |           documentation: new Map(),
 992 |         });
 993 | 
 994 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
 995 |         {
 996 |           filePath: "src/api.ts",
 997 |           hasDrift: true,
 998 |           severity: "medium",
 999 |           drifts: [
1000 |             {
1001 |               type: "outdated",
1002 |               affectedDocs: [docPath],
1003 |               codeChanges: [
1004 |                 {
1005 |                   type: "modified",
1006 |                   category: "function",
1007 |                   name: "oldFunction",
1008 |                   details: "Function renamed to newFunction",
1009 |                   impactLevel: "major",
1010 |                 },
1011 |               ],
1012 |               description: "Function signature changed",
1013 |               detectedAt: "2025-01-01T00:00:00.000Z",
1014 |               severity: "medium",
1015 |             },
1016 |           ],
1017 |           impactAnalysis: {
1018 |             breakingChanges: 0,
1019 |             majorChanges: 1,
1020 |             minorChanges: 0,
1021 |             affectedDocFiles: [docPath],
1022 |             estimatedUpdateEffort: "medium",
1023 |             requiresManualReview: false,
1024 |           },
1025 |           suggestions: [
1026 |             {
1027 |               docFile: docPath,
1028 |               section: "oldFunction",
1029 |               currentContent: "This is outdated.",
1030 |               suggestedContent: `## newFunction
1031 | 
1032 | Updated documentation for new function.`,
1033 |               reasoning: "Function was renamed from oldFunction to newFunction",
1034 |               confidence: 0.95,
1035 |               autoApplicable: true,
1036 |             },
1037 |           ],
1038 |         },
1039 |       ]);
1040 | 
1041 |       // Run in apply mode
1042 |       const result = await handleSyncCodeToDocs({
1043 |         projectPath,
1044 |         docsPath,
1045 |         mode: "apply",
1046 |         autoApplyThreshold: 0.8,
1047 |       });
1048 | 
1049 |       const data = JSON.parse(result.content[0].text);
1050 |       expect(data.success).toBe(true);
1051 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1052 | 
1053 |       // Verify the file was actually modified
1054 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1055 |       expect(updatedDoc).toContain("newFunction");
1056 |     });
1057 | 
1058 |     test("should not apply low-confidence suggestions", async () => {
1059 |       const docPath = join(docsPath, "lowconf.md");
1060 |       const originalDoc = `# Low Confidence
1061 | 
1062 | ## someFunction
1063 | 
1064 | Original content.`;
1065 |       await fs.writeFile(docPath, originalDoc);
1066 | 
1067 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1068 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1069 |         timestamp: "2025-01-01T00:00:00.000Z",
1070 |         projectPath,
1071 |         files: new Map(),
1072 |         documentation: new Map(),
1073 |       });
1074 | 
1075 |       jest
1076 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1077 |         .mockResolvedValue({
1078 |           timestamp: "2025-01-01T00:00:00.000Z",
1079 |           projectPath,
1080 |           files: new Map(),
1081 |           documentation: new Map(),
1082 |         });
1083 | 
1084 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1085 |         {
1086 |           filePath: "src/lowconf.ts",
1087 |           hasDrift: true,
1088 |           severity: "low",
1089 |           drifts: [
1090 |             {
1091 |               type: "outdated",
1092 |               affectedDocs: [docPath],
1093 |               codeChanges: [
1094 |                 {
1095 |                   type: "modified",
1096 |                   category: "function",
1097 |                   name: "someFunction",
1098 |                   details: "Minor change",
1099 |                   impactLevel: "minor",
1100 |                 },
1101 |               ],
1102 |               description: "Minor change",
1103 |               detectedAt: "2025-01-01T00:00:00.000Z",
1104 |               severity: "low",
1105 |             },
1106 |           ],
1107 |           impactAnalysis: {
1108 |             breakingChanges: 0,
1109 |             majorChanges: 0,
1110 |             minorChanges: 1,
1111 |             affectedDocFiles: [docPath],
1112 |             estimatedUpdateEffort: "low",
1113 |             requiresManualReview: false,
1114 |           },
1115 |           suggestions: [
1116 |             {
1117 |               docFile: docPath,
1118 |               section: "someFunction",
1119 |               currentContent: "Original content.",
1120 |               suggestedContent: "Suggested content.",
1121 |               reasoning: "Minor update needed",
1122 |               confidence: 0.5, // Low confidence
1123 |               autoApplicable: true,
1124 |             },
1125 |           ],
1126 |         },
1127 |       ]);
1128 | 
1129 |       const result = await handleSyncCodeToDocs({
1130 |         projectPath,
1131 |         docsPath,
1132 |         mode: "apply",
1133 |         autoApplyThreshold: 0.8, // Higher than suggestion confidence
1134 |       });
1135 | 
1136 |       const data = JSON.parse(result.content[0].text);
1137 |       expect(data.success).toBe(true);
1138 |       expect(data.data.pendingChanges.length).toBeGreaterThan(0);
1139 |       expect(data.data.appliedChanges.length).toBe(0);
1140 | 
1141 |       // Verify file was NOT modified
1142 |       const unchangedDoc = await fs.readFile(docPath, "utf-8");
1143 |       expect(unchangedDoc).toBe(originalDoc);
1144 |     });
1145 | 
1146 |     test("should apply all suggestions in auto mode regardless of confidence", async () => {
1147 |       const docPath = join(docsPath, "auto.md");
1148 |       const originalDoc = `# Auto Mode
1149 | 
1150 | ## function1
1151 | 
1152 | Old content.`;
1153 |       await fs.writeFile(docPath, originalDoc);
1154 | 
1155 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1156 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1157 |         timestamp: "2025-01-01T00:00:00.000Z",
1158 |         projectPath,
1159 |         files: new Map(),
1160 |         documentation: new Map(),
1161 |       });
1162 | 
1163 |       jest
1164 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1165 |         .mockResolvedValue({
1166 |           timestamp: "2025-01-01T00:00:00.000Z",
1167 |           projectPath,
1168 |           files: new Map(),
1169 |           documentation: new Map(),
1170 |         });
1171 | 
1172 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1173 |         {
1174 |           filePath: "src/auto.ts",
1175 |           hasDrift: true,
1176 |           severity: "low",
1177 |           drifts: [
1178 |             {
1179 |               type: "outdated",
1180 |               affectedDocs: [docPath],
1181 |               codeChanges: [
1182 |                 {
1183 |                   type: "modified",
1184 |                   category: "function",
1185 |                   name: "function1",
1186 |                   details: "Change",
1187 |                   impactLevel: "minor",
1188 |                 },
1189 |               ],
1190 |               description: "Change",
1191 |               detectedAt: "2025-01-01T00:00:00.000Z",
1192 |               severity: "low",
1193 |             },
1194 |           ],
1195 |           impactAnalysis: {
1196 |             breakingChanges: 0,
1197 |             majorChanges: 0,
1198 |             minorChanges: 1,
1199 |             affectedDocFiles: [docPath],
1200 |             estimatedUpdateEffort: "low",
1201 |             requiresManualReview: false,
1202 |           },
1203 |           suggestions: [
1204 |             {
1205 |               docFile: docPath,
1206 |               section: "function1",
1207 |               currentContent: "Old content.",
1208 |               suggestedContent: `## function1
1209 | 
1210 | New content from auto mode.`,
1211 |               reasoning: "Auto-applied update",
1212 |               confidence: 0.3, // Very low confidence
1213 |               autoApplicable: false, // Not auto-applicable
1214 |             },
1215 |           ],
1216 |         },
1217 |       ]);
1218 | 
1219 |       const result = await handleSyncCodeToDocs({
1220 |         projectPath,
1221 |         docsPath,
1222 |         mode: "auto", // Auto mode applies everything
1223 |       });
1224 | 
1225 |       const data = JSON.parse(result.content[0].text);
1226 |       expect(data.success).toBe(true);
1227 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1228 | 
1229 |       // Verify file was modified
1230 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1231 |       expect(updatedDoc).toContain("New content from auto mode");
1232 |     });
1233 | 
1234 |     test("should handle apply errors and mark as pending", async () => {
1235 |       const docPath = join(docsPath, "error.md");
1236 |       // Don't create the file - this will cause an error
1237 | 
1238 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1239 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1240 |         timestamp: "2025-01-01T00:00:00.000Z",
1241 |         projectPath,
1242 |         files: new Map(),
1243 |         documentation: new Map(),
1244 |       });
1245 | 
1246 |       jest
1247 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1248 |         .mockResolvedValue({
1249 |           timestamp: "2025-01-01T00:00:00.000Z",
1250 |           projectPath,
1251 |           files: new Map(),
1252 |           documentation: new Map(),
1253 |         });
1254 | 
1255 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1256 |         {
1257 |           filePath: "src/error.ts",
1258 |           hasDrift: true,
1259 |           severity: "medium",
1260 |           drifts: [
1261 |             {
1262 |               type: "outdated",
1263 |               affectedDocs: [docPath],
1264 |               codeChanges: [
1265 |                 {
1266 |                   type: "modified",
1267 |                   category: "function",
1268 |                   name: "errorFunction",
1269 |                   details: "Change",
1270 |                   impactLevel: "minor",
1271 |                 },
1272 |               ],
1273 |               description: "Change",
1274 |               detectedAt: "2025-01-01T00:00:00.000Z",
1275 |               severity: "medium",
1276 |             },
1277 |           ],
1278 |           impactAnalysis: {
1279 |             breakingChanges: 0,
1280 |             majorChanges: 1,
1281 |             minorChanges: 0,
1282 |             affectedDocFiles: [docPath],
1283 |             estimatedUpdateEffort: "medium",
1284 |             requiresManualReview: false,
1285 |           },
1286 |           suggestions: [
1287 |             {
1288 |               docFile: docPath, // File doesn't exist
1289 |               section: "errorSection",
1290 |               currentContent: "N/A",
1291 |               suggestedContent: "New content",
1292 |               reasoning: "Should fail",
1293 |               confidence: 0.95,
1294 |               autoApplicable: true,
1295 |             },
1296 |           ],
1297 |         },
1298 |       ]);
1299 | 
1300 |       const mockContext = {
1301 |         info: jest.fn(),
1302 |         warn: jest.fn(),
1303 |       };
1304 | 
1305 |       const result = await handleSyncCodeToDocs(
1306 |         {
1307 |           projectPath,
1308 |           docsPath,
1309 |           mode: "apply",
1310 |           autoApplyThreshold: 0.8,
1311 |         },
1312 |         mockContext,
1313 |       );
1314 | 
1315 |       const data = JSON.parse(result.content[0].text);
1316 |       expect(data.success).toBe(true);
1317 |       // Failed applies should be added to pending changes
1318 |       expect(data.data.pendingChanges.length).toBeGreaterThan(0);
1319 |       expect(mockContext.warn).toHaveBeenCalled();
1320 |     });
1321 | 
1322 |     test("should add new section when section doesn't exist", async () => {
1323 |       const docPath = join(docsPath, "newsection.md");
1324 |       const originalDoc = `# New Section Test
1325 | 
1326 | ## existingSection
1327 | 
1328 | Existing content.`;
1329 |       await fs.writeFile(docPath, originalDoc);
1330 | 
1331 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1332 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1333 |         timestamp: "2025-01-01T00:00:00.000Z",
1334 |         projectPath,
1335 |         files: new Map(),
1336 |         documentation: new Map(),
1337 |       });
1338 | 
1339 |       jest
1340 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1341 |         .mockResolvedValue({
1342 |           timestamp: "2025-01-01T00:00:00.000Z",
1343 |           projectPath,
1344 |           files: new Map(),
1345 |           documentation: new Map(),
1346 |         });
1347 | 
1348 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1349 |         {
1350 |           filePath: "src/new.ts",
1351 |           hasDrift: true,
1352 |           severity: "low",
1353 |           drifts: [
1354 |             {
1355 |               type: "missing",
1356 |               affectedDocs: [docPath],
1357 |               codeChanges: [
1358 |                 {
1359 |                   type: "added",
1360 |                   category: "function",
1361 |                   name: "newFunction",
1362 |                   details: "New function added",
1363 |                   impactLevel: "minor",
1364 |                 },
1365 |               ],
1366 |               description: "New function",
1367 |               detectedAt: "2025-01-01T00:00:00.000Z",
1368 |               severity: "low",
1369 |             },
1370 |           ],
1371 |           impactAnalysis: {
1372 |             breakingChanges: 0,
1373 |             majorChanges: 0,
1374 |             minorChanges: 1,
1375 |             affectedDocFiles: [docPath],
1376 |             estimatedUpdateEffort: "low",
1377 |             requiresManualReview: false,
1378 |           },
1379 |           suggestions: [
1380 |             {
1381 |               docFile: docPath,
1382 |               section: "newSection", // This section doesn't exist
1383 |               currentContent: "",
1384 |               suggestedContent: `## newSection
1385 | 
1386 | This is a brand new section.`,
1387 |               reasoning: "New function added",
1388 |               confidence: 0.9,
1389 |               autoApplicable: true,
1390 |             },
1391 |           ],
1392 |         },
1393 |       ]);
1394 | 
1395 |       const result = await handleSyncCodeToDocs({
1396 |         projectPath,
1397 |         docsPath,
1398 |         mode: "apply",
1399 |         autoApplyThreshold: 0.8,
1400 |       });
1401 | 
1402 |       const data = JSON.parse(result.content[0].text);
1403 |       expect(data.success).toBe(true);
1404 |       expect(data.data.appliedChanges.length).toBeGreaterThan(0);
1405 | 
1406 |       // Verify new section was appended
1407 |       const updatedDoc = await fs.readFile(docPath, "utf-8");
1408 |       expect(updatedDoc).toContain("newSection");
1409 |       expect(updatedDoc).toContain("brand new section");
1410 |     });
1411 | 
1412 |     test("should handle breaking changes recommendation", async () => {
1413 |       const docPath = join(docsPath, "breaking.md");
1414 |       await fs.writeFile(docPath, "# Breaking");
1415 | 
1416 |       jest.spyOn(DriftDetector.prototype, "initialize").mockResolvedValue();
1417 |       jest.spyOn(DriftDetector.prototype, "createSnapshot").mockResolvedValue({
1418 |         timestamp: "2025-01-01T00:00:00.000Z",
1419 |         projectPath,
1420 |         files: new Map(),
1421 |         documentation: new Map(),
1422 |       });
1423 | 
1424 |       jest
1425 |         .spyOn(DriftDetector.prototype, "loadLatestSnapshot")
1426 |         .mockResolvedValue({
1427 |           timestamp: "2025-01-01T00:00:00.000Z",
1428 |           projectPath,
1429 |           files: new Map(),
1430 |           documentation: new Map(),
1431 |         });
1432 | 
1433 |       jest.spyOn(DriftDetector.prototype, "detectDrift").mockResolvedValue([
1434 |         {
1435 |           filePath: "src/breaking.ts",
1436 |           hasDrift: true,
1437 |           severity: "critical",
1438 |           drifts: [
1439 |             {
1440 |               type: "breaking",
1441 |               affectedDocs: [docPath],
1442 |               codeChanges: [
1443 |                 {
1444 |                   type: "removed",
1445 |                   category: "function",
1446 |                   name: "oldAPI",
1447 |                   details: "Breaking change",
1448 |                   impactLevel: "breaking",
1449 |                 },
1450 |               ],
1451 |               description: "Breaking change",
1452 |               detectedAt: "2025-01-01T00:00:00.000Z",
1453 |               severity: "critical",
1454 |             },
1455 |           ],
1456 |           impactAnalysis: {
1457 |             breakingChanges: 2, // Multiple breaking changes
1458 |             majorChanges: 0,
1459 |             minorChanges: 0,
1460 |             affectedDocFiles: [docPath],
1461 |             estimatedUpdateEffort: "high",
1462 |             requiresManualReview: true,
1463 |           },
1464 |           suggestions: [
1465 |             {
1466 |               docFile: docPath,
1467 |               section: "API",
1468 |               currentContent: "Old API",
1469 |               suggestedContent: "New API",
1470 |               reasoning: "Breaking change",
1471 |               confidence: 0.9,
1472 |               autoApplicable: true,
1473 |             },
1474 |           ],
1475 |         },
1476 |       ]);
1477 | 
1478 |       const result = await handleSyncCodeToDocs({
1479 |         projectPath,
1480 |         docsPath,
1481 |         mode: "detect",
1482 |       });
1483 | 
1484 |       const data = JSON.parse(result.content[0].text);
1485 |       expect(data.success).toBe(true);
1486 |       expect(data.data.stats.breakingChanges).toBe(2);
1487 | 
1488 |       // Should have critical recommendation
1489 |       const criticalRec = data.recommendations.find(
1490 |         (r: any) => r.type === "critical",
1491 |       );
1492 |       expect(criticalRec).toBeDefined();
1493 |       expect(criticalRec.title).toContain("Breaking");
1494 |     });
1495 | 
1496 |     afterEach(() => {
1497 |       jest.restoreAllMocks();
1498 |     });
1499 |   });
1500 | });
1501 | 
```

--------------------------------------------------------------------------------
/docs/api/assets/style.css:
--------------------------------------------------------------------------------

```css
   1 | @layer typedoc {
   2 |     :root {
   3 |         --dim-toolbar-contents-height: 2.5rem;
   4 |         --dim-toolbar-border-bottom-width: 1px;
   5 |         --dim-header-height: calc(
   6 |             var(--dim-toolbar-border-bottom-width) +
   7 |                 var(--dim-toolbar-contents-height)
   8 |         );
   9 | 
  10 |         /* 0rem For mobile; unit is required for calculation in `calc` */
  11 |         --dim-container-main-margin-y: 0rem;
  12 | 
  13 |         --dim-footer-height: 3.5rem;
  14 | 
  15 |         --modal-animation-duration: 0.2s;
  16 |     }
  17 | 
  18 |     :root {
  19 |         /* Light */
  20 |         --light-color-background: #f2f4f8;
  21 |         --light-color-background-secondary: #eff0f1;
  22 |         /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */
  23 |         --light-color-background-active: #d6d8da;
  24 |         --light-color-background-warning: #e6e600;
  25 |         --light-color-warning-text: #222;
  26 |         --light-color-accent: #c5c7c9;
  27 |         --light-color-active-menu-item: var(--light-color-background-active);
  28 |         --light-color-text: #222;
  29 |         --light-color-contrast-text: #000;
  30 |         --light-color-text-aside: #5e5e5e;
  31 | 
  32 |         --light-color-icon-background: var(--light-color-background);
  33 |         --light-color-icon-text: var(--light-color-text);
  34 | 
  35 |         --light-color-comment-tag-text: var(--light-color-text);
  36 |         --light-color-comment-tag: var(--light-color-background);
  37 | 
  38 |         --light-color-link: #1f70c2;
  39 |         --light-color-focus-outline: #3584e4;
  40 | 
  41 |         --light-color-ts-keyword: #056bd6;
  42 |         --light-color-ts-project: #b111c9;
  43 |         --light-color-ts-module: var(--light-color-ts-project);
  44 |         --light-color-ts-namespace: var(--light-color-ts-project);
  45 |         --light-color-ts-enum: #7e6f15;
  46 |         --light-color-ts-enum-member: var(--light-color-ts-enum);
  47 |         --light-color-ts-variable: #4760ec;
  48 |         --light-color-ts-function: #572be7;
  49 |         --light-color-ts-class: #1f70c2;
  50 |         --light-color-ts-interface: #108024;
  51 |         --light-color-ts-constructor: var(--light-color-ts-class);
  52 |         --light-color-ts-property: #9f5f30;
  53 |         --light-color-ts-method: #be3989;
  54 |         --light-color-ts-reference: #ff4d82;
  55 |         --light-color-ts-call-signature: var(--light-color-ts-method);
  56 |         --light-color-ts-index-signature: var(--light-color-ts-property);
  57 |         --light-color-ts-constructor-signature: var(
  58 |             --light-color-ts-constructor
  59 |         );
  60 |         --light-color-ts-parameter: var(--light-color-ts-variable);
  61 |         /* type literal not included as links will never be generated to it */
  62 |         --light-color-ts-type-parameter: #a55c0e;
  63 |         --light-color-ts-accessor: #c73c3c;
  64 |         --light-color-ts-get-signature: var(--light-color-ts-accessor);
  65 |         --light-color-ts-set-signature: var(--light-color-ts-accessor);
  66 |         --light-color-ts-type-alias: #d51270;
  67 |         /* reference not included as links will be colored with the kind that it points to */
  68 |         --light-color-document: #000000;
  69 | 
  70 |         --light-color-alert-note: #0969d9;
  71 |         --light-color-alert-tip: #1a7f37;
  72 |         --light-color-alert-important: #8250df;
  73 |         --light-color-alert-warning: #9a6700;
  74 |         --light-color-alert-caution: #cf222e;
  75 | 
  76 |         --light-external-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' width='10' height='10'><path fill-opacity='0' stroke='%23000' stroke-width='10' d='m43,35H5v60h60V57M45,5v10l10,10-30,30 20,20 30-30 10,10h10V5z'/></svg>");
  77 |         --light-color-scheme: light;
  78 |     }
  79 | 
  80 |     :root {
  81 |         /* Dark */
  82 |         --dark-color-background: #2b2e33;
  83 |         --dark-color-background-secondary: #1e2024;
  84 |         /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */
  85 |         --dark-color-background-active: #5d5d6a;
  86 |         --dark-color-background-warning: #bebe00;
  87 |         --dark-color-warning-text: #222;
  88 |         --dark-color-accent: #9096a2;
  89 |         --dark-color-active-menu-item: var(--dark-color-background-active);
  90 |         --dark-color-text: #f5f5f5;
  91 |         --dark-color-contrast-text: #ffffff;
  92 |         --dark-color-text-aside: #dddddd;
  93 | 
  94 |         --dark-color-icon-background: var(--dark-color-background-secondary);
  95 |         --dark-color-icon-text: var(--dark-color-text);
  96 | 
  97 |         --dark-color-comment-tag-text: var(--dark-color-text);
  98 |         --dark-color-comment-tag: var(--dark-color-background);
  99 | 
 100 |         --dark-color-link: #00aff4;
 101 |         --dark-color-focus-outline: #4c97f2;
 102 | 
 103 |         --dark-color-ts-keyword: #3399ff;
 104 |         --dark-color-ts-project: #e358ff;
 105 |         --dark-color-ts-module: var(--dark-color-ts-project);
 106 |         --dark-color-ts-namespace: var(--dark-color-ts-project);
 107 |         --dark-color-ts-enum: #f4d93e;
 108 |         --dark-color-ts-enum-member: var(--dark-color-ts-enum);
 109 |         --dark-color-ts-variable: #798dff;
 110 |         --dark-color-ts-function: #a280ff;
 111 |         --dark-color-ts-class: #8ac4ff;
 112 |         --dark-color-ts-interface: #6cff87;
 113 |         --dark-color-ts-constructor: var(--dark-color-ts-class);
 114 |         --dark-color-ts-property: #ff984d;
 115 |         --dark-color-ts-method: #ff4db8;
 116 |         --dark-color-ts-reference: #ff4d82;
 117 |         --dark-color-ts-call-signature: var(--dark-color-ts-method);
 118 |         --dark-color-ts-index-signature: var(--dark-color-ts-property);
 119 |         --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor);
 120 |         --dark-color-ts-parameter: var(--dark-color-ts-variable);
 121 |         /* type literal not included as links will never be generated to it */
 122 |         --dark-color-ts-type-parameter: #e07d13;
 123 |         --dark-color-ts-accessor: #ff6060;
 124 |         --dark-color-ts-get-signature: var(--dark-color-ts-accessor);
 125 |         --dark-color-ts-set-signature: var(--dark-color-ts-accessor);
 126 |         --dark-color-ts-type-alias: #ff6492;
 127 |         /* reference not included as links will be colored with the kind that it points to */
 128 |         --dark-color-document: #ffffff;
 129 | 
 130 |         --dark-color-alert-note: #0969d9;
 131 |         --dark-color-alert-tip: #1a7f37;
 132 |         --dark-color-alert-important: #8250df;
 133 |         --dark-color-alert-warning: #9a6700;
 134 |         --dark-color-alert-caution: #cf222e;
 135 | 
 136 |         --dark-external-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' width='10' height='10'><path fill-opacity='0' stroke='%23fff' stroke-width='10' d='m43,35H5v60h60V57M45,5v10l10,10-30,30 20,20 30-30 10,10h10V5z'/></svg>");
 137 |         --dark-color-scheme: dark;
 138 |     }
 139 | 
 140 |     @media (prefers-color-scheme: light) {
 141 |         :root {
 142 |             --color-background: var(--light-color-background);
 143 |             --color-background-secondary: var(
 144 |                 --light-color-background-secondary
 145 |             );
 146 |             --color-background-active: var(--light-color-background-active);
 147 |             --color-background-warning: var(--light-color-background-warning);
 148 |             --color-warning-text: var(--light-color-warning-text);
 149 |             --color-accent: var(--light-color-accent);
 150 |             --color-active-menu-item: var(--light-color-active-menu-item);
 151 |             --color-text: var(--light-color-text);
 152 |             --color-contrast-text: var(--light-color-contrast-text);
 153 |             --color-text-aside: var(--light-color-text-aside);
 154 | 
 155 |             --color-icon-background: var(--light-color-icon-background);
 156 |             --color-icon-text: var(--light-color-icon-text);
 157 | 
 158 |             --color-comment-tag-text: var(--light-color-text);
 159 |             --color-comment-tag: var(--light-color-background);
 160 | 
 161 |             --color-link: var(--light-color-link);
 162 |             --color-focus-outline: var(--light-color-focus-outline);
 163 | 
 164 |             --color-ts-keyword: var(--light-color-ts-keyword);
 165 |             --color-ts-project: var(--light-color-ts-project);
 166 |             --color-ts-module: var(--light-color-ts-module);
 167 |             --color-ts-namespace: var(--light-color-ts-namespace);
 168 |             --color-ts-enum: var(--light-color-ts-enum);
 169 |             --color-ts-enum-member: var(--light-color-ts-enum-member);
 170 |             --color-ts-variable: var(--light-color-ts-variable);
 171 |             --color-ts-function: var(--light-color-ts-function);
 172 |             --color-ts-class: var(--light-color-ts-class);
 173 |             --color-ts-interface: var(--light-color-ts-interface);
 174 |             --color-ts-constructor: var(--light-color-ts-constructor);
 175 |             --color-ts-property: var(--light-color-ts-property);
 176 |             --color-ts-method: var(--light-color-ts-method);
 177 |             --color-ts-reference: var(--light-color-ts-reference);
 178 |             --color-ts-call-signature: var(--light-color-ts-call-signature);
 179 |             --color-ts-index-signature: var(--light-color-ts-index-signature);
 180 |             --color-ts-constructor-signature: var(
 181 |                 --light-color-ts-constructor-signature
 182 |             );
 183 |             --color-ts-parameter: var(--light-color-ts-parameter);
 184 |             --color-ts-type-parameter: var(--light-color-ts-type-parameter);
 185 |             --color-ts-accessor: var(--light-color-ts-accessor);
 186 |             --color-ts-get-signature: var(--light-color-ts-get-signature);
 187 |             --color-ts-set-signature: var(--light-color-ts-set-signature);
 188 |             --color-ts-type-alias: var(--light-color-ts-type-alias);
 189 |             --color-document: var(--light-color-document);
 190 | 
 191 |             --color-alert-note: var(--light-color-alert-note);
 192 |             --color-alert-tip: var(--light-color-alert-tip);
 193 |             --color-alert-important: var(--light-color-alert-important);
 194 |             --color-alert-warning: var(--light-color-alert-warning);
 195 |             --color-alert-caution: var(--light-color-alert-caution);
 196 | 
 197 |             --external-icon: var(--light-external-icon);
 198 |             --color-scheme: var(--light-color-scheme);
 199 |         }
 200 |     }
 201 | 
 202 |     @media (prefers-color-scheme: dark) {
 203 |         :root {
 204 |             --color-background: var(--dark-color-background);
 205 |             --color-background-secondary: var(
 206 |                 --dark-color-background-secondary
 207 |             );
 208 |             --color-background-active: var(--dark-color-background-active);
 209 |             --color-background-warning: var(--dark-color-background-warning);
 210 |             --color-warning-text: var(--dark-color-warning-text);
 211 |             --color-accent: var(--dark-color-accent);
 212 |             --color-active-menu-item: var(--dark-color-active-menu-item);
 213 |             --color-text: var(--dark-color-text);
 214 |             --color-contrast-text: var(--dark-color-contrast-text);
 215 |             --color-text-aside: var(--dark-color-text-aside);
 216 | 
 217 |             --color-icon-background: var(--dark-color-icon-background);
 218 |             --color-icon-text: var(--dark-color-icon-text);
 219 | 
 220 |             --color-comment-tag-text: var(--dark-color-text);
 221 |             --color-comment-tag: var(--dark-color-background);
 222 | 
 223 |             --color-link: var(--dark-color-link);
 224 |             --color-focus-outline: var(--dark-color-focus-outline);
 225 | 
 226 |             --color-ts-keyword: var(--dark-color-ts-keyword);
 227 |             --color-ts-project: var(--dark-color-ts-project);
 228 |             --color-ts-module: var(--dark-color-ts-module);
 229 |             --color-ts-namespace: var(--dark-color-ts-namespace);
 230 |             --color-ts-enum: var(--dark-color-ts-enum);
 231 |             --color-ts-enum-member: var(--dark-color-ts-enum-member);
 232 |             --color-ts-variable: var(--dark-color-ts-variable);
 233 |             --color-ts-function: var(--dark-color-ts-function);
 234 |             --color-ts-class: var(--dark-color-ts-class);
 235 |             --color-ts-interface: var(--dark-color-ts-interface);
 236 |             --color-ts-constructor: var(--dark-color-ts-constructor);
 237 |             --color-ts-property: var(--dark-color-ts-property);
 238 |             --color-ts-method: var(--dark-color-ts-method);
 239 |             --color-ts-reference: var(--dark-color-ts-reference);
 240 |             --color-ts-call-signature: var(--dark-color-ts-call-signature);
 241 |             --color-ts-index-signature: var(--dark-color-ts-index-signature);
 242 |             --color-ts-constructor-signature: var(
 243 |                 --dark-color-ts-constructor-signature
 244 |             );
 245 |             --color-ts-parameter: var(--dark-color-ts-parameter);
 246 |             --color-ts-type-parameter: var(--dark-color-ts-type-parameter);
 247 |             --color-ts-accessor: var(--dark-color-ts-accessor);
 248 |             --color-ts-get-signature: var(--dark-color-ts-get-signature);
 249 |             --color-ts-set-signature: var(--dark-color-ts-set-signature);
 250 |             --color-ts-type-alias: var(--dark-color-ts-type-alias);
 251 |             --color-document: var(--dark-color-document);
 252 | 
 253 |             --color-alert-note: var(--dark-color-alert-note);
 254 |             --color-alert-tip: var(--dark-color-alert-tip);
 255 |             --color-alert-important: var(--dark-color-alert-important);
 256 |             --color-alert-warning: var(--dark-color-alert-warning);
 257 |             --color-alert-caution: var(--dark-color-alert-caution);
 258 | 
 259 |             --external-icon: var(--dark-external-icon);
 260 |             --color-scheme: var(--dark-color-scheme);
 261 |         }
 262 |     }
 263 | 
 264 |     :root[data-theme="light"] {
 265 |         --color-background: var(--light-color-background);
 266 |         --color-background-secondary: var(--light-color-background-secondary);
 267 |         --color-background-active: var(--light-color-background-active);
 268 |         --color-background-warning: var(--light-color-background-warning);
 269 |         --color-warning-text: var(--light-color-warning-text);
 270 |         --color-icon-background: var(--light-color-icon-background);
 271 |         --color-accent: var(--light-color-accent);
 272 |         --color-active-menu-item: var(--light-color-active-menu-item);
 273 |         --color-text: var(--light-color-text);
 274 |         --color-contrast-text: var(--light-color-contrast-text);
 275 |         --color-text-aside: var(--light-color-text-aside);
 276 |         --color-icon-text: var(--light-color-icon-text);
 277 | 
 278 |         --color-comment-tag-text: var(--light-color-text);
 279 |         --color-comment-tag: var(--light-color-background);
 280 | 
 281 |         --color-link: var(--light-color-link);
 282 |         --color-focus-outline: var(--light-color-focus-outline);
 283 | 
 284 |         --color-ts-keyword: var(--light-color-ts-keyword);
 285 |         --color-ts-project: var(--light-color-ts-project);
 286 |         --color-ts-module: var(--light-color-ts-module);
 287 |         --color-ts-namespace: var(--light-color-ts-namespace);
 288 |         --color-ts-enum: var(--light-color-ts-enum);
 289 |         --color-ts-enum-member: var(--light-color-ts-enum-member);
 290 |         --color-ts-variable: var(--light-color-ts-variable);
 291 |         --color-ts-function: var(--light-color-ts-function);
 292 |         --color-ts-class: var(--light-color-ts-class);
 293 |         --color-ts-interface: var(--light-color-ts-interface);
 294 |         --color-ts-constructor: var(--light-color-ts-constructor);
 295 |         --color-ts-property: var(--light-color-ts-property);
 296 |         --color-ts-method: var(--light-color-ts-method);
 297 |         --color-ts-reference: var(--light-color-ts-reference);
 298 |         --color-ts-call-signature: var(--light-color-ts-call-signature);
 299 |         --color-ts-index-signature: var(--light-color-ts-index-signature);
 300 |         --color-ts-constructor-signature: var(
 301 |             --light-color-ts-constructor-signature
 302 |         );
 303 |         --color-ts-parameter: var(--light-color-ts-parameter);
 304 |         --color-ts-type-parameter: var(--light-color-ts-type-parameter);
 305 |         --color-ts-accessor: var(--light-color-ts-accessor);
 306 |         --color-ts-get-signature: var(--light-color-ts-get-signature);
 307 |         --color-ts-set-signature: var(--light-color-ts-set-signature);
 308 |         --color-ts-type-alias: var(--light-color-ts-type-alias);
 309 |         --color-document: var(--light-color-document);
 310 | 
 311 |         --color-note: var(--light-color-note);
 312 |         --color-tip: var(--light-color-tip);
 313 |         --color-important: var(--light-color-important);
 314 |         --color-warning: var(--light-color-warning);
 315 |         --color-caution: var(--light-color-caution);
 316 | 
 317 |         --external-icon: var(--light-external-icon);
 318 |         --color-scheme: var(--light-color-scheme);
 319 |     }
 320 | 
 321 |     :root[data-theme="dark"] {
 322 |         --color-background: var(--dark-color-background);
 323 |         --color-background-secondary: var(--dark-color-background-secondary);
 324 |         --color-background-active: var(--dark-color-background-active);
 325 |         --color-background-warning: var(--dark-color-background-warning);
 326 |         --color-warning-text: var(--dark-color-warning-text);
 327 |         --color-icon-background: var(--dark-color-icon-background);
 328 |         --color-accent: var(--dark-color-accent);
 329 |         --color-active-menu-item: var(--dark-color-active-menu-item);
 330 |         --color-text: var(--dark-color-text);
 331 |         --color-contrast-text: var(--dark-color-contrast-text);
 332 |         --color-text-aside: var(--dark-color-text-aside);
 333 |         --color-icon-text: var(--dark-color-icon-text);
 334 | 
 335 |         --color-comment-tag-text: var(--dark-color-text);
 336 |         --color-comment-tag: var(--dark-color-background);
 337 | 
 338 |         --color-link: var(--dark-color-link);
 339 |         --color-focus-outline: var(--dark-color-focus-outline);
 340 | 
 341 |         --color-ts-keyword: var(--dark-color-ts-keyword);
 342 |         --color-ts-project: var(--dark-color-ts-project);
 343 |         --color-ts-module: var(--dark-color-ts-module);
 344 |         --color-ts-namespace: var(--dark-color-ts-namespace);
 345 |         --color-ts-enum: var(--dark-color-ts-enum);
 346 |         --color-ts-enum-member: var(--dark-color-ts-enum-member);
 347 |         --color-ts-variable: var(--dark-color-ts-variable);
 348 |         --color-ts-function: var(--dark-color-ts-function);
 349 |         --color-ts-class: var(--dark-color-ts-class);
 350 |         --color-ts-interface: var(--dark-color-ts-interface);
 351 |         --color-ts-constructor: var(--dark-color-ts-constructor);
 352 |         --color-ts-property: var(--dark-color-ts-property);
 353 |         --color-ts-method: var(--dark-color-ts-method);
 354 |         --color-ts-reference: var(--dark-color-ts-reference);
 355 |         --color-ts-call-signature: var(--dark-color-ts-call-signature);
 356 |         --color-ts-index-signature: var(--dark-color-ts-index-signature);
 357 |         --color-ts-constructor-signature: var(
 358 |             --dark-color-ts-constructor-signature
 359 |         );
 360 |         --color-ts-parameter: var(--dark-color-ts-parameter);
 361 |         --color-ts-type-parameter: var(--dark-color-ts-type-parameter);
 362 |         --color-ts-accessor: var(--dark-color-ts-accessor);
 363 |         --color-ts-get-signature: var(--dark-color-ts-get-signature);
 364 |         --color-ts-set-signature: var(--dark-color-ts-set-signature);
 365 |         --color-ts-type-alias: var(--dark-color-ts-type-alias);
 366 |         --color-document: var(--dark-color-document);
 367 | 
 368 |         --color-note: var(--dark-color-note);
 369 |         --color-tip: var(--dark-color-tip);
 370 |         --color-important: var(--dark-color-important);
 371 |         --color-warning: var(--dark-color-warning);
 372 |         --color-caution: var(--dark-color-caution);
 373 | 
 374 |         --external-icon: var(--dark-external-icon);
 375 |         --color-scheme: var(--dark-color-scheme);
 376 |     }
 377 | 
 378 |     html {
 379 |         color-scheme: var(--color-scheme);
 380 |         @media (prefers-reduced-motion: no-preference) {
 381 |             scroll-behavior: smooth;
 382 |         }
 383 |     }
 384 | 
 385 |     *:focus-visible,
 386 |     .tsd-accordion-summary:focus-visible svg {
 387 |         outline: 2px solid var(--color-focus-outline);
 388 |     }
 389 | 
 390 |     .always-visible,
 391 |     .always-visible .tsd-signatures {
 392 |         display: inherit !important;
 393 |     }
 394 | 
 395 |     h1,
 396 |     h2,
 397 |     h3,
 398 |     h4,
 399 |     h5,
 400 |     h6 {
 401 |         line-height: 1.2;
 402 |     }
 403 | 
 404 |     h1 {
 405 |         font-size: 1.875rem;
 406 |         margin: 0.67rem 0;
 407 |     }
 408 | 
 409 |     h2 {
 410 |         font-size: 1.5rem;
 411 |         margin: 0.83rem 0;
 412 |     }
 413 | 
 414 |     h3 {
 415 |         font-size: 1.25rem;
 416 |         margin: 1rem 0;
 417 |     }
 418 | 
 419 |     h4 {
 420 |         font-size: 1.05rem;
 421 |         margin: 1.33rem 0;
 422 |     }
 423 | 
 424 |     h5 {
 425 |         font-size: 1rem;
 426 |         margin: 1.5rem 0;
 427 |     }
 428 | 
 429 |     h6 {
 430 |         font-size: 0.875rem;
 431 |         margin: 2.33rem 0;
 432 |     }
 433 | 
 434 |     dl,
 435 |     menu,
 436 |     ol,
 437 |     ul {
 438 |         margin: 1em 0;
 439 |     }
 440 | 
 441 |     dd {
 442 |         margin: 0 0 0 34px;
 443 |     }
 444 | 
 445 |     .container {
 446 |         max-width: 1700px;
 447 |         padding: 0 2rem;
 448 |     }
 449 | 
 450 |     /* Footer */
 451 |     footer {
 452 |         border-top: 1px solid var(--color-accent);
 453 |         padding-top: 1rem;
 454 |         padding-bottom: 1rem;
 455 |         max-height: var(--dim-footer-height);
 456 |     }
 457 |     footer > p {
 458 |         margin: 0 1em;
 459 |     }
 460 | 
 461 |     .container-main {
 462 |         margin: var(--dim-container-main-margin-y) auto;
 463 |         /* toolbar, footer, margin */
 464 |         min-height: calc(
 465 |             100svh - var(--dim-header-height) - var(--dim-footer-height) -
 466 |                 2 * var(--dim-container-main-margin-y)
 467 |         );
 468 |     }
 469 | 
 470 |     @keyframes fade-in {
 471 |         from {
 472 |             opacity: 0;
 473 |         }
 474 |         to {
 475 |             opacity: 1;
 476 |         }
 477 |     }
 478 |     @keyframes fade-out {
 479 |         from {
 480 |             opacity: 1;
 481 |             visibility: visible;
 482 |         }
 483 |         to {
 484 |             opacity: 0;
 485 |         }
 486 |     }
 487 |     @keyframes pop-in-from-right {
 488 |         from {
 489 |             transform: translate(100%, 0);
 490 |         }
 491 |         to {
 492 |             transform: translate(0, 0);
 493 |         }
 494 |     }
 495 |     @keyframes pop-out-to-right {
 496 |         from {
 497 |             transform: translate(0, 0);
 498 |             visibility: visible;
 499 |         }
 500 |         to {
 501 |             transform: translate(100%, 0);
 502 |         }
 503 |     }
 504 |     body {
 505 |         background: var(--color-background);
 506 |         font-family:
 507 |             -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
 508 |             Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
 509 |         font-size: 16px;
 510 |         color: var(--color-text);
 511 |         margin: 0;
 512 |     }
 513 | 
 514 |     a {
 515 |         color: var(--color-link);
 516 |         text-decoration: none;
 517 |     }
 518 |     a:hover {
 519 |         text-decoration: underline;
 520 |     }
 521 |     a.external[target="_blank"] {
 522 |         background-image: var(--external-icon);
 523 |         background-position: top 3px right;
 524 |         background-repeat: no-repeat;
 525 |         padding-right: 13px;
 526 |     }
 527 |     a.tsd-anchor-link {
 528 |         color: var(--color-text);
 529 |     }
 530 |     :target {
 531 |         scroll-margin-block: calc(var(--dim-header-height) + 0.5rem);
 532 |     }
 533 | 
 534 |     code,
 535 |     pre {
 536 |         font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
 537 |         padding: 0.2em;
 538 |         margin: 0;
 539 |         font-size: 0.875rem;
 540 |         border-radius: 0.8em;
 541 |     }
 542 | 
 543 |     pre {
 544 |         position: relative;
 545 |         white-space: pre-wrap;
 546 |         word-wrap: break-word;
 547 |         padding: 10px;
 548 |         border: 1px solid var(--color-accent);
 549 |         margin-bottom: 8px;
 550 |     }
 551 |     pre code {
 552 |         padding: 0;
 553 |         font-size: 100%;
 554 |     }
 555 |     pre > button {
 556 |         position: absolute;
 557 |         top: 10px;
 558 |         right: 10px;
 559 |         opacity: 0;
 560 |         transition: opacity 0.1s;
 561 |         box-sizing: border-box;
 562 |     }
 563 |     pre:hover > button,
 564 |     pre > button.visible,
 565 |     pre > button:focus-visible {
 566 |         opacity: 1;
 567 |     }
 568 | 
 569 |     blockquote {
 570 |         margin: 1em 0;
 571 |         padding-left: 1em;
 572 |         border-left: 4px solid gray;
 573 |     }
 574 | 
 575 |     img {
 576 |         max-width: 100%;
 577 |     }
 578 | 
 579 |     * {
 580 |         scrollbar-width: thin;
 581 |         scrollbar-color: var(--color-accent) var(--color-icon-background);
 582 |     }
 583 | 
 584 |     *::-webkit-scrollbar {
 585 |         width: 0.75rem;
 586 |     }
 587 | 
 588 |     *::-webkit-scrollbar-track {
 589 |         background: var(--color-icon-background);
 590 |     }
 591 | 
 592 |     *::-webkit-scrollbar-thumb {
 593 |         background-color: var(--color-accent);
 594 |         border-radius: 999rem;
 595 |         border: 0.25rem solid var(--color-icon-background);
 596 |     }
 597 | 
 598 |     dialog {
 599 |         border: none;
 600 |         outline: none;
 601 |         padding: 0;
 602 |         background-color: var(--color-background);
 603 |     }
 604 |     dialog::backdrop {
 605 |         display: none;
 606 |     }
 607 |     #tsd-overlay {
 608 |         background-color: rgba(0, 0, 0, 0.5);
 609 |         position: fixed;
 610 |         z-index: 9999;
 611 |         top: 0;
 612 |         left: 0;
 613 |         right: 0;
 614 |         bottom: 0;
 615 |         animation: fade-in var(--modal-animation-duration) forwards;
 616 |     }
 617 |     #tsd-overlay.closing {
 618 |         animation-name: fade-out;
 619 |     }
 620 | 
 621 |     .tsd-typography {
 622 |         line-height: 1.333em;
 623 |     }
 624 |     .tsd-typography ul {
 625 |         list-style: square;
 626 |         padding: 0 0 0 20px;
 627 |         margin: 0;
 628 |     }
 629 |     .tsd-typography .tsd-index-panel h3,
 630 |     .tsd-index-panel .tsd-typography h3,
 631 |     .tsd-typography h4,
 632 |     .tsd-typography h5,
 633 |     .tsd-typography h6 {
 634 |         font-size: 1em;
 635 |     }
 636 |     .tsd-typography h5,
 637 |     .tsd-typography h6 {
 638 |         font-weight: normal;
 639 |     }
 640 |     .tsd-typography p,
 641 |     .tsd-typography ul,
 642 |     .tsd-typography ol {
 643 |         margin: 1em 0;
 644 |     }
 645 |     .tsd-typography table {
 646 |         border-collapse: collapse;
 647 |         border: none;
 648 |     }
 649 |     .tsd-typography td,
 650 |     .tsd-typography th {
 651 |         padding: 6px 13px;
 652 |         border: 1px solid var(--color-accent);
 653 |     }
 654 |     .tsd-typography thead,
 655 |     .tsd-typography tr:nth-child(even) {
 656 |         background-color: var(--color-background-secondary);
 657 |     }
 658 | 
 659 |     .tsd-alert {
 660 |         padding: 8px 16px;
 661 |         margin-bottom: 16px;
 662 |         border-left: 0.25em solid var(--alert-color);
 663 |     }
 664 |     .tsd-alert blockquote > :last-child,
 665 |     .tsd-alert > :last-child {
 666 |         margin-bottom: 0;
 667 |     }
 668 |     .tsd-alert-title {
 669 |         color: var(--alert-color);
 670 |         display: inline-flex;
 671 |         align-items: center;
 672 |     }
 673 |     .tsd-alert-title span {
 674 |         margin-left: 4px;
 675 |     }
 676 | 
 677 |     .tsd-alert-note {
 678 |         --alert-color: var(--color-alert-note);
 679 |     }
 680 |     .tsd-alert-tip {
 681 |         --alert-color: var(--color-alert-tip);
 682 |     }
 683 |     .tsd-alert-important {
 684 |         --alert-color: var(--color-alert-important);
 685 |     }
 686 |     .tsd-alert-warning {
 687 |         --alert-color: var(--color-alert-warning);
 688 |     }
 689 |     .tsd-alert-caution {
 690 |         --alert-color: var(--color-alert-caution);
 691 |     }
 692 | 
 693 |     .tsd-breadcrumb {
 694 |         margin: 0;
 695 |         margin-top: 1rem;
 696 |         padding: 0;
 697 |         color: var(--color-text-aside);
 698 |     }
 699 |     .tsd-breadcrumb a {
 700 |         color: var(--color-text-aside);
 701 |         text-decoration: none;
 702 |     }
 703 |     .tsd-breadcrumb a:hover {
 704 |         text-decoration: underline;
 705 |     }
 706 |     .tsd-breadcrumb li {
 707 |         display: inline;
 708 |     }
 709 |     .tsd-breadcrumb li:after {
 710 |         content: " / ";
 711 |     }
 712 | 
 713 |     .tsd-comment-tags {
 714 |         display: flex;
 715 |         flex-direction: column;
 716 |     }
 717 |     dl.tsd-comment-tag-group {
 718 |         display: flex;
 719 |         align-items: center;
 720 |         overflow: hidden;
 721 |         margin: 0.5em 0;
 722 |     }
 723 |     dl.tsd-comment-tag-group dt {
 724 |         display: flex;
 725 |         margin-right: 0.5em;
 726 |         font-size: 0.875em;
 727 |         font-weight: normal;
 728 |     }
 729 |     dl.tsd-comment-tag-group dd {
 730 |         margin: 0;
 731 |     }
 732 |     code.tsd-tag {
 733 |         padding: 0.25em 0.4em;
 734 |         border: 0.1em solid var(--color-accent);
 735 |         margin-right: 0.25em;
 736 |         font-size: 70%;
 737 |     }
 738 |     h1 code.tsd-tag:first-of-type {
 739 |         margin-left: 0.25em;
 740 |     }
 741 | 
 742 |     dl.tsd-comment-tag-group dd:before,
 743 |     dl.tsd-comment-tag-group dd:after {
 744 |         content: " ";
 745 |     }
 746 |     dl.tsd-comment-tag-group dd pre,
 747 |     dl.tsd-comment-tag-group dd:after {
 748 |         clear: both;
 749 |     }
 750 |     dl.tsd-comment-tag-group p {
 751 |         margin: 0;
 752 |     }
 753 | 
 754 |     .tsd-panel.tsd-comment .lead {
 755 |         font-size: 1.1em;
 756 |         line-height: 1.333em;
 757 |         margin-bottom: 2em;
 758 |     }
 759 |     .tsd-panel.tsd-comment .lead:last-child {
 760 |         margin-bottom: 0;
 761 |     }
 762 | 
 763 |     .tsd-filter-visibility h4 {
 764 |         font-size: 1rem;
 765 |         padding-top: 0.75rem;
 766 |         padding-bottom: 0.5rem;
 767 |         margin: 0;
 768 |     }
 769 |     .tsd-filter-item:not(:last-child) {
 770 |         margin-bottom: 0.5rem;
 771 |     }
 772 |     .tsd-filter-input {
 773 |         display: flex;
 774 |         width: -moz-fit-content;
 775 |         width: fit-content;
 776 |         align-items: center;
 777 |         -webkit-user-select: none;
 778 |         -moz-user-select: none;
 779 |         -ms-user-select: none;
 780 |         user-select: none;
 781 |         cursor: pointer;
 782 |     }
 783 |     .tsd-filter-input input[type="checkbox"] {
 784 |         cursor: pointer;
 785 |         position: absolute;
 786 |         width: 1.5em;
 787 |         height: 1.5em;
 788 |         opacity: 0;
 789 |     }
 790 |     .tsd-filter-input input[type="checkbox"]:disabled {
 791 |         pointer-events: none;
 792 |     }
 793 |     .tsd-filter-input svg {
 794 |         cursor: pointer;
 795 |         width: 1.5em;
 796 |         height: 1.5em;
 797 |         margin-right: 0.5em;
 798 |         border-radius: 0.33em;
 799 |         /* Leaving this at full opacity breaks event listeners on Firefox.
 800 |         Don't remove unless you know what you're doing. */
 801 |         opacity: 0.99;
 802 |     }
 803 |     .tsd-filter-input input[type="checkbox"]:focus-visible + svg {
 804 |         outline: 2px solid var(--color-focus-outline);
 805 |     }
 806 |     .tsd-checkbox-background {
 807 |         fill: var(--color-accent);
 808 |     }
 809 |     input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark {
 810 |         stroke: var(--color-text);
 811 |     }
 812 |     .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background {
 813 |         fill: var(--color-background);
 814 |         stroke: var(--color-accent);
 815 |         stroke-width: 0.25rem;
 816 |     }
 817 |     .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark {
 818 |         stroke: var(--color-accent);
 819 |     }
 820 | 
 821 |     .settings-label {
 822 |         font-weight: bold;
 823 |         text-transform: uppercase;
 824 |         display: inline-block;
 825 |     }
 826 | 
 827 |     .tsd-filter-visibility .settings-label {
 828 |         margin: 0.75rem 0 0.5rem 0;
 829 |     }
 830 | 
 831 |     .tsd-theme-toggle .settings-label {
 832 |         margin: 0.75rem 0.75rem 0 0;
 833 |     }
 834 | 
 835 |     .tsd-hierarchy h4 label:hover span {
 836 |         text-decoration: underline;
 837 |     }
 838 | 
 839 |     .tsd-hierarchy {
 840 |         list-style: square;
 841 |         margin: 0;
 842 |     }
 843 |     .tsd-hierarchy-target {
 844 |         font-weight: bold;
 845 |     }
 846 |     .tsd-hierarchy-toggle {
 847 |         color: var(--color-link);
 848 |         cursor: pointer;
 849 |     }
 850 | 
 851 |     .tsd-full-hierarchy:not(:last-child) {
 852 |         margin-bottom: 1em;
 853 |         padding-bottom: 1em;
 854 |         border-bottom: 1px solid var(--color-accent);
 855 |     }
 856 |     .tsd-full-hierarchy,
 857 |     .tsd-full-hierarchy ul {
 858 |         list-style: none;
 859 |         margin: 0;
 860 |         padding: 0;
 861 |     }
 862 |     .tsd-full-hierarchy ul {
 863 |         padding-left: 1.5rem;
 864 |     }
 865 |     .tsd-full-hierarchy a {
 866 |         padding: 0.25rem 0 !important;
 867 |         font-size: 1rem;
 868 |         display: inline-flex;
 869 |         align-items: center;
 870 |         color: var(--color-text);
 871 |     }
 872 |     .tsd-full-hierarchy svg[data-dropdown] {
 873 |         cursor: pointer;
 874 |     }
 875 |     .tsd-full-hierarchy svg[data-dropdown="false"] {
 876 |         transform: rotate(-90deg);
 877 |     }
 878 |     .tsd-full-hierarchy svg[data-dropdown="false"] ~ ul {
 879 |         display: none;
 880 |     }
 881 | 
 882 |     .tsd-panel-group.tsd-index-group {
 883 |         margin-bottom: 0;
 884 |     }
 885 |     .tsd-index-panel .tsd-index-list {
 886 |         list-style: none;
 887 |         line-height: 1.333em;
 888 |         margin: 0;
 889 |         padding: 0.25rem 0 0 0;
 890 |         overflow: hidden;
 891 |         display: grid;
 892 |         grid-template-columns: repeat(3, 1fr);
 893 |         column-gap: 1rem;
 894 |         grid-template-rows: auto;
 895 |     }
 896 |     @media (max-width: 1024px) {
 897 |         .tsd-index-panel .tsd-index-list {
 898 |             grid-template-columns: repeat(2, 1fr);
 899 |         }
 900 |     }
 901 |     @media (max-width: 768px) {
 902 |         .tsd-index-panel .tsd-index-list {
 903 |             grid-template-columns: repeat(1, 1fr);
 904 |         }
 905 |     }
 906 |     .tsd-index-panel .tsd-index-list li {
 907 |         -webkit-page-break-inside: avoid;
 908 |         -moz-page-break-inside: avoid;
 909 |         -ms-page-break-inside: avoid;
 910 |         -o-page-break-inside: avoid;
 911 |         page-break-inside: avoid;
 912 |     }
 913 | 
 914 |     .tsd-flag {
 915 |         display: inline-block;
 916 |         padding: 0.25em 0.4em;
 917 |         border-radius: 4px;
 918 |         color: var(--color-comment-tag-text);
 919 |         background-color: var(--color-comment-tag);
 920 |         text-indent: 0;
 921 |         font-size: 75%;
 922 |         line-height: 1;
 923 |         font-weight: normal;
 924 |     }
 925 | 
 926 |     .tsd-anchor {
 927 |         position: relative;
 928 |         top: -100px;
 929 |     }
 930 | 
 931 |     .tsd-member {
 932 |         position: relative;
 933 |     }
 934 |     .tsd-member .tsd-anchor + h3 {
 935 |         display: flex;
 936 |         align-items: center;
 937 |         margin-top: 0;
 938 |         margin-bottom: 0;
 939 |         border-bottom: none;
 940 |     }
 941 | 
 942 |     .tsd-navigation.settings {
 943 |         margin: 0;
 944 |         margin-bottom: 1rem;
 945 |     }
 946 |     .tsd-navigation > a,
 947 |     .tsd-navigation .tsd-accordion-summary {
 948 |         width: calc(100% - 0.25rem);
 949 |         display: flex;
 950 |         align-items: center;
 951 |     }
 952 |     .tsd-navigation a,
 953 |     .tsd-navigation summary > span,
 954 |     .tsd-page-navigation a {
 955 |         display: flex;
 956 |         width: calc(100% - 0.25rem);
 957 |         align-items: center;
 958 |         padding: 0.25rem;
 959 |         color: var(--color-text);
 960 |         text-decoration: none;
 961 |         box-sizing: border-box;
 962 |     }
 963 |     .tsd-navigation a.current,
 964 |     .tsd-page-navigation a.current {
 965 |         background: var(--color-active-menu-item);
 966 |         color: var(--color-contrast-text);
 967 |     }
 968 |     .tsd-navigation a:hover,
 969 |     .tsd-page-navigation a:hover {
 970 |         text-decoration: underline;
 971 |     }
 972 |     .tsd-navigation ul,
 973 |     .tsd-page-navigation ul {
 974 |         margin-top: 0;
 975 |         margin-bottom: 0;
 976 |         padding: 0;
 977 |         list-style: none;
 978 |     }
 979 |     .tsd-navigation li,
 980 |     .tsd-page-navigation li {
 981 |         padding: 0;
 982 |         max-width: 100%;
 983 |     }
 984 |     .tsd-navigation .tsd-nav-link {
 985 |         display: none;
 986 |     }
 987 |     .tsd-nested-navigation {
 988 |         margin-left: 3rem;
 989 |     }
 990 |     .tsd-nested-navigation > li > details {
 991 |         margin-left: -1.5rem;
 992 |     }
 993 |     .tsd-small-nested-navigation {
 994 |         margin-left: 1.5rem;
 995 |     }
 996 |     .tsd-small-nested-navigation > li > details {
 997 |         margin-left: -1.5rem;
 998 |     }
 999 | 
1000 |     .tsd-page-navigation-section > summary {
1001 |         padding: 0.25rem;
1002 |     }
1003 |     .tsd-page-navigation-section > summary > svg {
1004 |         margin-right: 0.25rem;
1005 |     }
1006 |     .tsd-page-navigation-section > div {
1007 |         margin-left: 30px;
1008 |     }
1009 |     .tsd-page-navigation ul {
1010 |         padding-left: 1.75rem;
1011 |     }
1012 | 
1013 |     #tsd-sidebar-links a {
1014 |         margin-top: 0;
1015 |         margin-bottom: 0.5rem;
1016 |         line-height: 1.25rem;
1017 |     }
1018 |     #tsd-sidebar-links a:last-of-type {
1019 |         margin-bottom: 0;
1020 |     }
1021 | 
1022 |     a.tsd-index-link {
1023 |         padding: 0.25rem 0 !important;
1024 |         font-size: 1rem;
1025 |         line-height: 1.25rem;
1026 |         display: inline-flex;
1027 |         align-items: center;
1028 |         color: var(--color-text);
1029 |     }
1030 |     .tsd-accordion-summary {
1031 |         list-style-type: none; /* hide marker on non-safari */
1032 |         outline: none; /* broken on safari, so just hide it */
1033 |         display: flex;
1034 |         align-items: center;
1035 |         gap: 0.25rem;
1036 |         box-sizing: border-box;
1037 |     }
1038 |     .tsd-accordion-summary::-webkit-details-marker {
1039 |         display: none; /* hide marker on safari */
1040 |     }
1041 |     .tsd-accordion-summary,
1042 |     .tsd-accordion-summary a {
1043 |         -moz-user-select: none;
1044 |         -webkit-user-select: none;
1045 |         -ms-user-select: none;
1046 |         user-select: none;
1047 | 
1048 |         cursor: pointer;
1049 |     }
1050 |     .tsd-accordion-summary a {
1051 |         width: calc(100% - 1.5rem);
1052 |     }
1053 |     .tsd-accordion-summary > * {
1054 |         margin-top: 0;
1055 |         margin-bottom: 0;
1056 |         padding-top: 0;
1057 |         padding-bottom: 0;
1058 |     }
1059 |     /*
1060 |      * We need to be careful to target the arrow indicating whether the accordion
1061 |      * is open, but not any other SVGs included in the details element.
1062 |      */
1063 |     .tsd-accordion:not([open]) > .tsd-accordion-summary > svg:first-child {
1064 |         transform: rotate(-90deg);
1065 |     }
1066 |     .tsd-index-content > :not(:first-child) {
1067 |         margin-top: 0.75rem;
1068 |     }
1069 |     .tsd-index-summary {
1070 |         margin-top: 1.5rem;
1071 |         margin-bottom: 0.75rem;
1072 |         display: flex;
1073 |         align-content: center;
1074 |     }
1075 | 
1076 |     .tsd-no-select {
1077 |         -webkit-user-select: none;
1078 |         -moz-user-select: none;
1079 |         -ms-user-select: none;
1080 |         user-select: none;
1081 |     }
1082 |     .tsd-kind-icon {
1083 |         margin-right: 0.5rem;
1084 |         width: 1.25rem;
1085 |         height: 1.25rem;
1086 |         min-width: 1.25rem;
1087 |         min-height: 1.25rem;
1088 |     }
1089 |     .tsd-signature > .tsd-kind-icon {
1090 |         margin-right: 0.8rem;
1091 |     }
1092 | 
1093 |     .tsd-panel {
1094 |         margin-bottom: 2.5rem;
1095 |     }
1096 |     .tsd-panel.tsd-member {
1097 |         margin-bottom: 4rem;
1098 |     }
1099 |     .tsd-panel:empty {
1100 |         display: none;
1101 |     }
1102 |     .tsd-panel > h1,
1103 |     .tsd-panel > h2,
1104 |     .tsd-panel > h3 {
1105 |         margin: 1.5rem -1.5rem 0.75rem -1.5rem;
1106 |         padding: 0 1.5rem 0.75rem 1.5rem;
1107 |     }
1108 |     .tsd-panel > h1.tsd-before-signature,
1109 |     .tsd-panel > h2.tsd-before-signature,
1110 |     .tsd-panel > h3.tsd-before-signature {
1111 |         margin-bottom: 0;
1112 |         border-bottom: none;
1113 |     }
1114 | 
1115 |     .tsd-panel-group {
1116 |         margin: 2rem 0;
1117 |     }
1118 |     .tsd-panel-group.tsd-index-group {
1119 |         margin: 2rem 0;
1120 |     }
1121 |     .tsd-panel-group.tsd-index-group details {
1122 |         margin: 2rem 0;
1123 |     }
1124 |     .tsd-panel-group > .tsd-accordion-summary {
1125 |         margin-bottom: 1rem;
1126 |     }
1127 | 
1128 |     #tsd-search[open] {
1129 |         animation: fade-in var(--modal-animation-duration) ease-out forwards;
1130 |     }
1131 |     #tsd-search[open].closing {
1132 |         animation-name: fade-out;
1133 |     }
1134 | 
1135 |     /* Avoid setting `display` on closed dialog */
1136 |     #tsd-search[open] {
1137 |         display: flex;
1138 |         flex-direction: column;
1139 |         padding: 1rem;
1140 |         width: 32rem;
1141 |         max-width: 90vw;
1142 |         max-height: calc(100vh - env(keyboard-inset-height, 0px) - 25vh);
1143 |         /* Anchor dialog to top */
1144 |         margin-top: 10vh;
1145 |         border-radius: 6px;
1146 |         will-change: max-height;
1147 |     }
1148 |     #tsd-search-input {
1149 |         box-sizing: border-box;
1150 |         width: 100%;
1151 |         padding: 0 0.625rem; /* 10px */
1152 |         outline: 0;
1153 |         border: 2px solid var(--color-accent);
1154 |         background-color: transparent;
1155 |         color: var(--color-text);
1156 |         border-radius: 4px;
1157 |         height: 2.5rem;
1158 |         flex: 0 0 auto;
1159 |         font-size: 0.875rem;
1160 |         transition: border-color 0.2s, background-color 0.2s;
1161 |     }
1162 |     #tsd-search-input:focus-visible {
1163 |         background-color: var(--color-background-active);
1164 |         border-color: transparent;
1165 |         color: var(--color-contrast-text);
1166 |     }
1167 |     #tsd-search-input::placeholder {
1168 |         color: inherit;
1169 |         opacity: 0.8;
1170 |     }
1171 |     #tsd-search-results {
1172 |         margin: 0;
1173 |         padding: 0;
1174 |         list-style: none;
1175 |         flex: 1 1 auto;
1176 |         display: flex;
1177 |         flex-direction: column;
1178 |         overflow-y: auto;
1179 |     }
1180 |     #tsd-search-results:not(:empty) {
1181 |         margin-top: 0.5rem;
1182 |     }
1183 |     #tsd-search-results > li {
1184 |         background-color: var(--color-background);
1185 |         line-height: 1.5;
1186 |         box-sizing: border-box;
1187 |         border-radius: 4px;
1188 |     }
1189 |     #tsd-search-results > li:nth-child(even) {
1190 |         background-color: var(--color-background-secondary);
1191 |     }
1192 |     #tsd-search-results > li:is(:hover, [aria-selected="true"]) {
1193 |         background-color: var(--color-background-active);
1194 |         color: var(--color-contrast-text);
1195 |     }
1196 |     /* It's important that this takes full size of parent `li`, to capture a click on `li` */
1197 |     #tsd-search-results > li > a {
1198 |         display: flex;
1199 |         align-items: center;
1200 |         padding: 0.5rem 0.25rem;
1201 |         box-sizing: border-box;
1202 |         width: 100%;
1203 |     }
1204 |     #tsd-search-results > li > a > .text {
1205 |         flex: 1 1 auto;
1206 |         min-width: 0;
1207 |         overflow-wrap: anywhere;
1208 |     }
1209 |     #tsd-search-results > li > a .parent {
1210 |         color: var(--color-text-aside);
1211 |     }
1212 |     #tsd-search-results > li > a mark {
1213 |         color: inherit;
1214 |         background-color: inherit;
1215 |         font-weight: bold;
1216 |     }
1217 |     #tsd-search-status {
1218 |         flex: 1;
1219 |         display: grid;
1220 |         place-content: center;
1221 |         text-align: center;
1222 |         overflow-wrap: anywhere;
1223 |     }
1224 |     #tsd-search-status:not(:empty) {
1225 |         min-height: 6rem;
1226 |     }
1227 | 
1228 |     .tsd-signature {
1229 |         margin: 0 0 1rem 0;
1230 |         padding: 1rem 0.5rem;
1231 |         border: 1px solid var(--color-accent);
1232 |         font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
1233 |         font-size: 14px;
1234 |         overflow-x: auto;
1235 |     }
1236 | 
1237 |     .tsd-signature-keyword {
1238 |         color: var(--color-ts-keyword);
1239 |         font-weight: normal;
1240 |     }
1241 | 
1242 |     .tsd-signature-symbol {
1243 |         color: var(--color-text-aside);
1244 |         font-weight: normal;
1245 |     }
1246 | 
1247 |     .tsd-signature-type {
1248 |         font-style: italic;
1249 |         font-weight: normal;
1250 |     }
1251 | 
1252 |     .tsd-signatures {
1253 |         padding: 0;
1254 |         margin: 0 0 1em 0;
1255 |         list-style-type: none;
1256 |     }
1257 |     .tsd-signatures .tsd-signature {
1258 |         margin: 0;
1259 |         border-color: var(--color-accent);
1260 |         border-width: 1px 0;
1261 |         transition: background-color 0.1s;
1262 |     }
1263 |     .tsd-signatures .tsd-index-signature:not(:last-child) {
1264 |         margin-bottom: 1em;
1265 |     }
1266 |     .tsd-signatures .tsd-index-signature .tsd-signature {
1267 |         border-width: 1px;
1268 |     }
1269 |     .tsd-description .tsd-signatures .tsd-signature {
1270 |         border-width: 1px;
1271 |     }
1272 | 
1273 |     ul.tsd-parameter-list,
1274 |     ul.tsd-type-parameter-list {
1275 |         list-style: square;
1276 |         margin: 0;
1277 |         padding-left: 20px;
1278 |     }
1279 |     ul.tsd-parameter-list > li.tsd-parameter-signature,
1280 |     ul.tsd-type-parameter-list > li.tsd-parameter-signature {
1281 |         list-style: none;
1282 |         margin-left: -20px;
1283 |     }
1284 |     ul.tsd-parameter-list h5,
1285 |     ul.tsd-type-parameter-list h5 {
1286 |         font-size: 16px;
1287 |         margin: 1em 0 0.5em 0;
1288 |     }
1289 |     .tsd-sources {
1290 |         margin-top: 1rem;
1291 |         font-size: 0.875em;
1292 |     }
1293 |     .tsd-sources a {
1294 |         color: var(--color-text-aside);
1295 |         text-decoration: underline;
1296 |     }
1297 |     .tsd-sources ul {
1298 |         list-style: none;
1299 |         padding: 0;
1300 |     }
1301 | 
1302 |     .tsd-page-toolbar {
1303 |         position: sticky;
1304 |         z-index: 1;
1305 |         top: 0;
1306 |         left: 0;
1307 |         width: 100%;
1308 |         color: var(--color-text);
1309 |         background: var(--color-background-secondary);
1310 |         border-bottom: var(--dim-toolbar-border-bottom-width)
1311 |             var(--color-accent) solid;
1312 |         transition: transform 0.3s ease-in-out;
1313 |     }
1314 |     .tsd-page-toolbar a {
1315 |         color: var(--color-text);
1316 |     }
1317 |     .tsd-toolbar-contents {
1318 |         display: flex;
1319 |         align-items: center;
1320 |         height: var(--dim-toolbar-contents-height);
1321 |         margin: 0 auto;
1322 |     }
1323 |     .tsd-toolbar-contents > .title {
1324 |         font-weight: bold;
1325 |         margin-right: auto;
1326 |     }
1327 |     #tsd-toolbar-links {
1328 |         display: flex;
1329 |         align-items: center;
1330 |         gap: 1.5rem;
1331 |         margin-right: 1rem;
1332 |     }
1333 | 
1334 |     .tsd-widget {
1335 |         box-sizing: border-box;
1336 |         display: inline-block;
1337 |         opacity: 0.8;
1338 |         height: 2.5rem;
1339 |         width: 2.5rem;
1340 |         transition: opacity 0.1s, background-color 0.1s;
1341 |         text-align: center;
1342 |         cursor: pointer;
1343 |         border: none;
1344 |         background-color: transparent;
1345 |     }
1346 |     .tsd-widget:hover {
1347 |         opacity: 0.9;
1348 |     }
1349 |     .tsd-widget:active {
1350 |         opacity: 1;
1351 |         background-color: var(--color-accent);
1352 |     }
1353 |     #tsd-toolbar-menu-trigger {
1354 |         display: none;
1355 |     }
1356 | 
1357 |     .tsd-member-summary-name {
1358 |         display: inline-flex;
1359 |         align-items: center;
1360 |         padding: 0.25rem;
1361 |         text-decoration: none;
1362 |     }
1363 | 
1364 |     .tsd-anchor-icon {
1365 |         display: inline-flex;
1366 |         align-items: center;
1367 |         margin-left: 0.5rem;
1368 |         color: var(--color-text);
1369 |         vertical-align: middle;
1370 |     }
1371 | 
1372 |     .tsd-anchor-icon svg {
1373 |         width: 1em;
1374 |         height: 1em;
1375 |         visibility: hidden;
1376 |     }
1377 | 
1378 |     .tsd-member-summary-name:hover > .tsd-anchor-icon svg,
1379 |     .tsd-anchor-link:hover > .tsd-anchor-icon svg,
1380 |     .tsd-anchor-icon:focus-visible svg {
1381 |         visibility: visible;
1382 |     }
1383 | 
1384 |     .deprecated {
1385 |         text-decoration: line-through !important;
1386 |     }
1387 | 
1388 |     .warning {
1389 |         padding: 1rem;
1390 |         color: var(--color-warning-text);
1391 |         background: var(--color-background-warning);
1392 |     }
1393 | 
1394 |     .tsd-kind-project {
1395 |         color: var(--color-ts-project);
1396 |     }
1397 |     .tsd-kind-module {
1398 |         color: var(--color-ts-module);
1399 |     }
1400 |     .tsd-kind-namespace {
1401 |         color: var(--color-ts-namespace);
1402 |     }
1403 |     .tsd-kind-enum {
1404 |         color: var(--color-ts-enum);
1405 |     }
1406 |     .tsd-kind-enum-member {
1407 |         color: var(--color-ts-enum-member);
1408 |     }
1409 |     .tsd-kind-variable {
1410 |         color: var(--color-ts-variable);
1411 |     }
1412 |     .tsd-kind-function {
1413 |         color: var(--color-ts-function);
1414 |     }
1415 |     .tsd-kind-class {
1416 |         color: var(--color-ts-class);
1417 |     }
1418 |     .tsd-kind-interface {
1419 |         color: var(--color-ts-interface);
1420 |     }
1421 |     .tsd-kind-constructor {
1422 |         color: var(--color-ts-constructor);
1423 |     }
1424 |     .tsd-kind-property {
1425 |         color: var(--color-ts-property);
1426 |     }
1427 |     .tsd-kind-method {
1428 |         color: var(--color-ts-method);
1429 |     }
1430 |     .tsd-kind-reference {
1431 |         color: var(--color-ts-reference);
1432 |     }
1433 |     .tsd-kind-call-signature {
1434 |         color: var(--color-ts-call-signature);
1435 |     }
1436 |     .tsd-kind-index-signature {
1437 |         color: var(--color-ts-index-signature);
1438 |     }
1439 |     .tsd-kind-constructor-signature {
1440 |         color: var(--color-ts-constructor-signature);
1441 |     }
1442 |     .tsd-kind-parameter {
1443 |         color: var(--color-ts-parameter);
1444 |     }
1445 |     .tsd-kind-type-parameter {
1446 |         color: var(--color-ts-type-parameter);
1447 |     }
1448 |     .tsd-kind-accessor {
1449 |         color: var(--color-ts-accessor);
1450 |     }
1451 |     .tsd-kind-get-signature {
1452 |         color: var(--color-ts-get-signature);
1453 |     }
1454 |     .tsd-kind-set-signature {
1455 |         color: var(--color-ts-set-signature);
1456 |     }
1457 |     .tsd-kind-type-alias {
1458 |         color: var(--color-ts-type-alias);
1459 |     }
1460 | 
1461 |     /* if we have a kind icon, don't color the text by kind */
1462 |     .tsd-kind-icon ~ span {
1463 |         color: var(--color-text);
1464 |     }
1465 | 
1466 |     /* mobile */
1467 |     @media (max-width: 769px) {
1468 |         #tsd-toolbar-menu-trigger {
1469 |             display: inline-block;
1470 |             /* temporary fix to vertically align, for compatibility */
1471 |             line-height: 2.5;
1472 |         }
1473 |         #tsd-toolbar-links {
1474 |             display: none;
1475 |         }
1476 | 
1477 |         .container-main {
1478 |             display: flex;
1479 |         }
1480 |         .col-content {
1481 |             float: none;
1482 |             max-width: 100%;
1483 |             width: 100%;
1484 |         }
1485 |         .col-sidebar {
1486 |             position: fixed !important;
1487 |             overflow-y: auto;
1488 |             -webkit-overflow-scrolling: touch;
1489 |             z-index: 1024;
1490 |             top: 0 !important;
1491 |             bottom: 0 !important;
1492 |             left: auto !important;
1493 |             right: 0 !important;
1494 |             padding: 1.5rem 1.5rem 0 0;
1495 |             width: 75vw;
1496 |             visibility: hidden;
1497 |             background-color: var(--color-background);
1498 |             transform: translate(100%, 0);
1499 |         }
1500 |         .col-sidebar > *:last-child {
1501 |             padding-bottom: 20px;
1502 |         }
1503 |         .overlay {
1504 |             content: "";
1505 |             display: block;
1506 |             position: fixed;
1507 |             z-index: 1023;
1508 |             top: 0;
1509 |             left: 0;
1510 |             right: 0;
1511 |             bottom: 0;
1512 |             background-color: rgba(0, 0, 0, 0.75);
1513 |             visibility: hidden;
1514 |         }
1515 | 
1516 |         .to-has-menu .overlay {
1517 |             animation: fade-in 0.4s;
1518 |         }
1519 | 
1520 |         .to-has-menu .col-sidebar {
1521 |             animation: pop-in-from-right 0.4s;
1522 |         }
1523 | 
1524 |         .from-has-menu .overlay {
1525 |             animation: fade-out 0.4s;
1526 |         }
1527 | 
1528 |         .from-has-menu .col-sidebar {
1529 |             animation: pop-out-to-right 0.4s;
1530 |         }
1531 | 
1532 |         .has-menu body {
1533 |             overflow: hidden;
1534 |         }
1535 |         .has-menu .overlay {
1536 |             visibility: visible;
1537 |         }
1538 |         .has-menu .col-sidebar {
1539 |             visibility: visible;
1540 |             transform: translate(0, 0);
1541 |             display: flex;
1542 |             flex-direction: column;
1543 |             gap: 1.5rem;
1544 |             max-height: 100vh;
1545 |             padding: 1rem 2rem;
1546 |         }
1547 |         .has-menu .tsd-navigation {
1548 |             max-height: 100%;
1549 |         }
1550 |         .tsd-navigation .tsd-nav-link {
1551 |             display: flex;
1552 |         }
1553 |     }
1554 | 
1555 |     /* one sidebar */
1556 |     @media (min-width: 770px) {
1557 |         .container-main {
1558 |             display: grid;
1559 |             grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
1560 |             grid-template-areas: "sidebar content";
1561 |             --dim-container-main-margin-y: 2rem;
1562 |         }
1563 | 
1564 |         .tsd-breadcrumb {
1565 |             margin-top: 0;
1566 |         }
1567 | 
1568 |         .col-sidebar {
1569 |             grid-area: sidebar;
1570 |         }
1571 |         .col-content {
1572 |             grid-area: content;
1573 |             padding: 0 1rem;
1574 |         }
1575 |     }
1576 |     @media (min-width: 770px) and (max-width: 1399px) {
1577 |         .col-sidebar {
1578 |             max-height: calc(
1579 |                 100vh - var(--dim-header-height) - var(--dim-footer-height) -
1580 |                     2 * var(--dim-container-main-margin-y)
1581 |             );
1582 |             overflow: auto;
1583 |             position: sticky;
1584 |             top: calc(
1585 |                 var(--dim-header-height) + var(--dim-container-main-margin-y)
1586 |             );
1587 |         }
1588 |         .site-menu {
1589 |             margin-top: 1rem;
1590 |         }
1591 |     }
1592 | 
1593 |     /* two sidebars */
1594 |     @media (min-width: 1200px) {
1595 |         .container-main {
1596 |             grid-template-columns:
1597 |                 minmax(0, 1fr) minmax(0, 2.5fr) minmax(
1598 |                 0,
1599 |                 20rem
1600 |             );
1601 |             grid-template-areas: "sidebar content toc";
1602 |         }
1603 | 
1604 |         .col-sidebar {
1605 |             display: contents;
1606 |         }
1607 | 
1608 |         .page-menu {
1609 |             grid-area: toc;
1610 |             padding-left: 1rem;
1611 |         }
1612 |         .site-menu {
1613 |             grid-area: sidebar;
1614 |         }
1615 | 
1616 |         .site-menu {
1617 |             margin-top: 0rem;
1618 |         }
1619 | 
1620 |         .page-menu,
1621 |         .site-menu {
1622 |             max-height: calc(
1623 |                 100vh - var(--dim-header-height) - var(--dim-footer-height) -
1624 |                     2 * var(--dim-container-main-margin-y)
1625 |             );
1626 |             overflow: auto;
1627 |             position: sticky;
1628 |             top: calc(
1629 |                 var(--dim-header-height) + var(--dim-container-main-margin-y)
1630 |             );
1631 |         }
1632 |     }
1633 | }
1634 | 
```
Page 23/29FirstPrevNextLast