From 7367c2ec978eb6a0eb192dd9ba984fe13151a6c3 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 23 Apr 2026 07:11:28 -0500 Subject: [PATCH 1/3] chore: initialize tessl with vendored mode and MCP configs Run tessl init to generate MCP configs for 5 agents (Claude Code, Gemini CLI, Codex, GitHub Copilot CLI, GitHub Copilot for VS Code). Track .mcp.json and .vscode/mcp.json for team sharing. Gitignore .tessl/session-data/ and .playwright-mcp/. --- .codex/config.toml | 4 ++++ .gemini/settings.json | 12 ++++++++++++ .gitignore | 9 +++++++-- .mcp.json | 12 ++++++++++++ .vscode/mcp.json | 12 ++++++++++++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 .codex/config.toml create mode 100644 .gemini/settings.json create mode 100644 .mcp.json create mode 100644 .vscode/mcp.json diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 000000000..433432493 --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,4 @@ +[mcp_servers.tessl] +type = "stdio" +command = "tessl" +args = [ "mcp", "start" ] diff --git a/.gemini/settings.json b/.gemini/settings.json new file mode 100644 index 000000000..ebfccaac7 --- /dev/null +++ b/.gemini/settings.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": [ + "mcp", + "start" + ] + } + } +} diff --git a/.gitignore b/.gitignore index 5bd4f9af0..2d020d366 100644 --- a/.gitignore +++ b/.gitignore @@ -398,7 +398,9 @@ replay_pid* # IDEs .idea/ -.vscode/ +.vscode/* +!.vscode/mcp.json +!.vscode/extensions.json # Nuitka **/dist-nuitka/** @@ -409,8 +411,11 @@ replay_pid* # Mac .DS_Store +# Playwright MCP +.playwright-mcp/ + # Tessl — .tessl/.gitignore handles tiles/RULES.md internally -.mcp.json +.tessl/session-data/ # Claude Code — track shared config, ignore local state .claude/* diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 000000000..ebfccaac7 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,12 @@ +{ + "mcpServers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": [ + "mcp", + "start" + ] + } + } +} diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 000000000..c290f9fb5 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,12 @@ +{ + "servers": { + "tessl": { + "type": "stdio", + "command": "tessl", + "args": [ + "mcp", + "start" + ] + } + } +} From 0eb4422b64c44c016366d168e684a22476207bba Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 23 Apr 2026 07:11:34 -0500 Subject: [PATCH 2/3] chore: add recommended VS Code extensions Ruff, Python, mypy, debugpy, Even Better TOML, EditorConfig, and GitHub Copilot. --- .vscode/extensions.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .vscode/extensions.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..e6c72a172 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "charliermarsh.ruff", + "ms-python.python", + "ms-python.mypy-type-checker", + "ms-python.debugpy", + "tamasfe.even-better-toml", + "EditorConfig.EditorConfig", + "github.copilot" + ] +} From 41bf1d2d635ca7d3d53643cc4b4e1393b6f39913 Mon Sep 17 00:00:00 2001 From: Kevin Turcios Date: Thu, 23 Apr 2026 07:14:42 -0500 Subject: [PATCH 3/3] chore: install 37 tessl doc tiles and add weekly update workflow Vendor documentation tiles for project dependencies: - Python (27): pytest, gitpython, libcst, jedi, tree-sitter, tomlkit, attrs, requests, pydantic, humanize, posthog, click, inquirer, sentry-sdk, parameterized, dill, rich, lxml, crosshair-tool, coverage, platformdirs, pygls, filelock, memray, mypy, uv, pytest-cov - JS/TS (6): jest, vitest, mocha, typescript, better-sqlite3, @babel/core - Java (4): gson, jacoco-agent, junit-jupiter, @babel/preset-typescript Add scheduled GitHub Action (weekly Monday 9am UTC) that updates existing tiles, attempts to install 21 missing tiles, and auto-prunes the list as they become available. --- .github/workflows/tessl-update.yml | 97 ++ .../docs/annotations.md | 405 ++++++ .../docs/configuration.md | 357 +++++ .../docs/index.md | 211 +++ .../docs/json-tree-model.md | 317 +++++ .../docs/object-serialization.md | 217 +++ .../docs/streaming-api.md | 396 ++++++ .../docs/type-adapters.md | 393 ++++++ .../tile.json | 7 + .../docs/index.md | 200 +++ .../tile.json | 7 + .../docs/assertions.md | 535 ++++++++ .../docs/conditional-execution.md | 438 +++++++ .../docs/core-testing.md | 571 ++++++++ .../docs/dynamic-tests.md | 395 ++++++ .../docs/extensions.md | 849 ++++++++++++ .../docs/index.md | 249 ++++ .../docs/parallel-execution.md | 536 ++++++++ .../docs/parameterized-tests.md | 902 +++++++++++++ .../tile.json | 7 + .../npm-babel--core/docs/configuration.md | 486 +++++++ .../tiles/tessl/npm-babel--core/docs/index.md | 398 ++++++ .../tessl/npm-babel--core/docs/parsing.md | 430 ++++++ .../npm-babel--core/docs/transformation.md | 327 +++++ .../tessl/npm-babel--core/docs/utilities.md | 564 ++++++++ .tessl/tiles/tessl/npm-babel--core/tile.json | 7 + .../docs/index.md | 376 ++++++ .../npm-babel--preset-typescript/tile.json | 7 + .../docs/database-management.md | 253 ++++ .../docs/database-utilities.md | 362 +++++ .../tessl/npm-better-sqlite3/docs/index.md | 280 ++++ .../docs/statement-execution.md | 354 +++++ .../docs/transaction-management.md | 318 +++++ .../docs/user-defined-functions.md | 410 ++++++ .../tiles/tessl/npm-better-sqlite3/tile.json | 7 + .tessl/tiles/tessl/npm-jest/docs/cli-usage.md | 407 ++++++ .../tessl/npm-jest/docs/configuration.md | 513 ++++++++ .tessl/tiles/tessl/npm-jest/docs/index.md | 212 +++ .../tessl/npm-jest/docs/test-discovery.md | 307 +++++ .../tiles/tessl/npm-jest/docs/test-runner.md | 280 ++++ .../tessl/npm-jest/docs/test-scheduling.md | 501 +++++++ .tessl/tiles/tessl/npm-jest/tile.json | 7 + .tessl/tiles/tessl/npm-mocha/docs/browser.md | 435 ++++++ .../tiles/tessl/npm-mocha/docs/cli-config.md | 457 +++++++ .../tiles/tessl/npm-mocha/docs/execution.md | 485 +++++++ .tessl/tiles/tessl/npm-mocha/docs/index.md | 235 ++++ .../tiles/tessl/npm-mocha/docs/interfaces.md | 356 +++++ .../tiles/tessl/npm-mocha/docs/reporters.md | 530 ++++++++ .tessl/tiles/tessl/npm-mocha/tile.json | 7 + .../tessl/npm-typescript/docs/ast/factory.md | 640 +++++++++ .../tessl/npm-typescript/docs/ast/nodes.md | 1166 +++++++++++++++++ .../npm-typescript/docs/ast/scanner-parser.md | 327 +++++ .../npm-typescript/docs/ast/type-guards.md | 133 ++ .../npm-typescript/docs/core/compilation.md | 589 +++++++++ .../tessl/npm-typescript/docs/core/config.md | 115 ++ .../docs/core/module-resolution.md | 241 ++++ .../docs/core/solution-builder.md | 401 ++++++ .../tiles/tessl/npm-typescript/docs/index.md | 373 ++++++ .../docs/language-service/api.md | 811 ++++++++++++ .../docs/language-service/completions.md | 152 +++ .../docs/language-service/formatting.md | 355 +++++ .../docs/language-service/navigation.md | 192 +++ .../docs/language-service/refactorings.md | 115 ++ .../docs/language-service/tsserver.md | 459 +++++++ .../docs/transformation/context.md | 79 ++ .../docs/transformation/emit-helpers.md | 151 +++ .../docs/transformation/transformers.md | 613 +++++++++ .../npm-typescript/docs/types/diagnostics.md | 279 ++++ .../npm-typescript/docs/types/type-checker.md | 640 +++++++++ .../docs/types/types-symbols.md | 440 +++++++ .../npm-typescript/docs/types/utilities.md | 22 + .../npm-typescript/docs/utilities/paths.md | 67 + .../npm-typescript/docs/utilities/printer.md | 76 ++ .../npm-typescript/docs/utilities/system.md | 711 ++++++++++ .../npm-typescript/docs/utilities/text.md | 70 + .../docs/utilities/transpilation.md | 72 + .tessl/tiles/tessl/npm-typescript/tile.json | 8 + .../tiles/tessl/npm-vitest/docs/assertions.md | 422 ++++++ .../tessl/npm-vitest/docs/benchmarking.md | 371 ++++++ .../tessl/npm-vitest/docs/browser-testing.md | 501 +++++++ .../tessl/npm-vitest/docs/configuration.md | 454 +++++++ .tessl/tiles/tessl/npm-vitest/docs/index.md | 311 +++++ .tessl/tiles/tessl/npm-vitest/docs/mocking.md | 505 +++++++ .../tiles/tessl/npm-vitest/docs/node-apis.md | 384 ++++++ .../tiles/tessl/npm-vitest/docs/reporters.md | 439 +++++++ .../tessl/npm-vitest/docs/test-definition.md | 382 ++++++ .tessl/tiles/tessl/npm-vitest/docs/timers.md | 688 ++++++++++ .../tessl/npm-vitest/docs/type-testing.md | 459 +++++++ .tessl/tiles/tessl/npm-vitest/tile.json | 7 + .../tessl/pypi-attrs/docs/class-definition.md | 285 ++++ .../pypi-attrs/docs/configuration-errors.md | 428 ++++++ .../pypi-attrs/docs/field-configuration.md | 307 +++++ .tessl/tiles/tessl/pypi-attrs/docs/index.md | 268 ++++ .../tiles/tessl/pypi-attrs/docs/utilities.md | 531 ++++++++ .../pypi-attrs/docs/validation-conversion.md | 540 ++++++++ .tessl/tiles/tessl/pypi-attrs/tile.json | 7 + .../pypi-click/docs/command-definition.md | 288 ++++ .../tessl/pypi-click/docs/core-classes.md | 351 +++++ .../pypi-click/docs/exception-handling.md | 448 +++++++ .tessl/tiles/tessl/pypi-click/docs/index.md | 168 +++ .../tessl/pypi-click/docs/parameter-types.md | 375 ++++++ .../tessl/pypi-click/docs/terminal-ui.md | 443 +++++++ .../tiles/tessl/pypi-click/docs/utilities.md | 570 ++++++++ .tessl/tiles/tessl/pypi-click/tile.json | 7 + .../tessl/pypi-coverage/docs/configuration.md | 483 +++++++ .../tessl/pypi-coverage/docs/core-coverage.md | 416 ++++++ .../tessl/pypi-coverage/docs/data-storage.md | 389 ++++++ .../tessl/pypi-coverage/docs/exceptions.md | 458 +++++++ .../tiles/tessl/pypi-coverage/docs/index.md | 251 ++++ .../tiles/tessl/pypi-coverage/docs/plugins.md | 649 +++++++++ .../tessl/pypi-coverage/docs/reporting.md | 453 +++++++ .tessl/tiles/tessl/pypi-coverage/tile.json | 7 + .../docs/behavioral-analysis.md | 420 ++++++ .../pypi-crosshair-tool/docs/cli-tools.md | 406 ++++++ .../docs/contract-system.md | 366 ++++++ .../tessl/pypi-crosshair-tool/docs/index.md | 256 ++++ .../docs/symbolic-execution.md | 464 +++++++ .../tiles/tessl/pypi-crosshair-tool/tile.json | 7 + .../tessl/pypi-dill/docs/configuration.md | 636 +++++++++ .../pypi-dill/docs/core-serialization.md | 285 ++++ .../tessl/pypi-dill/docs/diagnostic-tools.md | 467 +++++++ .tessl/tiles/tessl/pypi-dill/docs/index.md | 453 +++++++ .../tessl/pypi-dill/docs/pickler-classes.md | 344 +++++ .../pypi-dill/docs/session-management.md | 361 +++++ .../tessl/pypi-dill/docs/source-analysis.md | 576 ++++++++ .../tessl/pypi-dill/docs/temp-operations.md | 705 ++++++++++ .../tessl/pypi-dill/docs/type-registry.md | 397 ++++++ .tessl/tiles/tessl/pypi-dill/tile.json | 7 + .../tiles/tessl/pypi-filelock/docs/index.md | 569 ++++++++ .tessl/tiles/tessl/pypi-filelock/tile.json | 7 + .../tessl/pypi-gitpython/docs/command.md | 53 + .../pypi-gitpython/docs/configuration.md | 58 + .../tessl/pypi-gitpython/docs/database.md | 124 ++ .../tiles/tessl/pypi-gitpython/docs/diff.md | 65 + .../tessl/pypi-gitpython/docs/exceptions.md | 139 ++ .../pypi-gitpython/docs/index-staging.md | 124 ++ .../tiles/tessl/pypi-gitpython/docs/index.md | 283 ++++ .../tessl/pypi-gitpython/docs/objects.md | 608 +++++++++ .../tessl/pypi-gitpython/docs/references.md | 123 ++ .../tiles/tessl/pypi-gitpython/docs/remote.md | 80 ++ .../tessl/pypi-gitpython/docs/repository.md | 313 +++++ .tessl/tiles/tessl/pypi-gitpython/tile.json | 7 + .../pypi-humanize/docs/filesize-formatting.md | 147 +++ .../tiles/tessl/pypi-humanize/docs/index.md | 145 ++ .../docs/internationalization.md | 261 ++++ .../pypi-humanize/docs/list-formatting.md | 171 +++ .../pypi-humanize/docs/number-formatting.md | 242 ++++ .../pypi-humanize/docs/time-formatting.md | 242 ++++ .tessl/tiles/tessl/pypi-humanize/tile.json | 7 + .../tiles/tessl/pypi-inquirer/docs/index.md | 200 +++ .../tessl/pypi-inquirer/docs/prompt-system.md | 334 +++++ .../pypi-inquirer/docs/question-types.md | 513 ++++++++ .../tessl/pypi-inquirer/docs/render-system.md | 258 ++++ .../tessl/pypi-inquirer/docs/shortcuts.md | 486 +++++++ .../tiles/tessl/pypi-inquirer/docs/themes.md | 426 ++++++ .tessl/tiles/tessl/pypi-inquirer/tile.json | 7 + .../tessl/pypi-jedi/docs/code-navigation.md | 388 ++++++ .../tessl/pypi-jedi/docs/code-refactoring.md | 486 +++++++ .../tessl/pypi-jedi/docs/configuration.md | 439 +++++++ .../pypi-jedi/docs/environment-management.md | 367 ++++++ .tessl/tiles/tessl/pypi-jedi/docs/index.md | 227 ++++ .../pypi-jedi/docs/interpreter-integration.md | 251 ++++ .../pypi-jedi/docs/project-configuration.md | 458 +++++++ .../tessl/pypi-jedi/docs/script-analysis.md | 358 +++++ .tessl/tiles/tessl/pypi-jedi/tile.json | 7 + .../tiles/tessl/pypi-libcst/docs/cli-tool.md | 312 +++++ .../tiles/tessl/pypi-libcst/docs/codemods.md | 561 ++++++++ .tessl/tiles/tessl/pypi-libcst/docs/index.md | 241 ++++ .../tiles/tessl/pypi-libcst/docs/matchers.md | 406 ++++++ .../tiles/tessl/pypi-libcst/docs/metadata.md | 479 +++++++ .tessl/tiles/tessl/pypi-libcst/docs/nodes.md | 758 +++++++++++ .../tiles/tessl/pypi-libcst/docs/parsing.md | 238 ++++ .../tiles/tessl/pypi-libcst/docs/utilities.md | 744 +++++++++++ .../tiles/tessl/pypi-libcst/docs/visitors.md | 319 +++++ .tessl/tiles/tessl/pypi-libcst/tile.json | 7 + .../tiles/tessl/pypi-lxml/docs/etree-core.md | 492 +++++++ .../tessl/pypi-lxml/docs/html-processing.md | 648 +++++++++ .tessl/tiles/tessl/pypi-lxml/docs/index.md | 334 +++++ .../tessl/pypi-lxml/docs/objectify-api.md | 534 ++++++++ .../tessl/pypi-lxml/docs/utility-modules.md | 823 ++++++++++++ .../tiles/tessl/pypi-lxml/docs/validation.md | 605 +++++++++ .../tiles/tessl/pypi-lxml/docs/xpath-xslt.md | 675 ++++++++++ .tessl/tiles/tessl/pypi-lxml/tile.json | 7 + .../tessl/pypi-memray/docs/cli-commands.md | 308 +++++ .../tiles/tessl/pypi-memray/docs/file-io.md | 323 +++++ .tessl/tiles/tessl/pypi-memray/docs/index.md | 249 ++++ .../pypi-memray/docs/ipython-integration.md | 241 ++++ .../tessl/pypi-memray/docs/memory-tracking.md | 175 +++ .tessl/tiles/tessl/pypi-memray/tile.json | 7 + .../tiles/tessl/pypi-mypy/docs/ast-nodes.md | 707 ++++++++++ .../tessl/pypi-mypy/docs/build-system.md | 539 ++++++++ .../pypi-mypy/docs/command-line-tools.md | 409 ++++++ .../tiles/tessl/pypi-mypy/docs/daemon-mode.md | 39 + .../tessl/pypi-mypy/docs/error-system.md | 657 ++++++++++ .tessl/tiles/tessl/pypi-mypy/docs/index.md | 398 ++++++ .../tessl/pypi-mypy/docs/mypyc-compiler.md | 108 ++ .../tessl/pypi-mypy/docs/plugin-system.md | 554 ++++++++ .../tessl/pypi-mypy/docs/programmatic-api.md | 303 +++++ .../tiles/tessl/pypi-mypy/docs/stub-tools.md | 450 +++++++ .../tiles/tessl/pypi-mypy/docs/type-system.md | 568 ++++++++ .tessl/tiles/tessl/pypi-mypy/tile.json | 7 + .../tessl/pypi-parameterized/docs/index.md | 353 +++++ .../tiles/tessl/pypi-parameterized/tile.json | 7 + .../pypi-platformdirs/docs/functional-api.md | 321 +++++ .../tessl/pypi-platformdirs/docs/index.md | 157 +++ .../docs/object-oriented-api.md | 267 ++++ .../docs/user-media-directories.md | 254 ++++ .../tiles/tessl/pypi-platformdirs/tile.json | 7 + .../pypi-posthog/docs/ai-integrations.md | 861 ++++++++++++ .../pypi-posthog/docs/client-management.md | 642 +++++++++ .../pypi-posthog/docs/context-management.md | 552 ++++++++ .../tessl/pypi-posthog/docs/event-tracking.md | 243 ++++ .../tessl/pypi-posthog/docs/feature-flags.md | 555 ++++++++ .tessl/tiles/tessl/pypi-posthog/docs/index.md | 302 +++++ .../docs/user-group-management.md | 367 ++++++ .tessl/tiles/tessl/pypi-posthog/tile.json | 7 + .../tessl/pypi-pydantic/docs/core-models.md | 364 +++++ .../docs/dataclasses-adapters.md | 466 +++++++ .../pypi-pydantic/docs/error-handling.md | 439 +++++++ .../tiles/tessl/pypi-pydantic/docs/index.md | 202 +++ .../tessl/pypi-pydantic/docs/json-schema.md | 400 ++++++ .../tiles/tessl/pypi-pydantic/docs/plugins.md | 474 +++++++ .../docs/serialization-config.md | 591 +++++++++ .../tessl/pypi-pydantic/docs/type-system.md | 766 +++++++++++ .../pypi-pydantic/docs/validation-system.md | 360 +++++ .tessl/tiles/tessl/pypi-pydantic/tile.json | 7 + .../pypi-pygls/docs/client-operations.md | 467 +++++++ .../pypi-pygls/docs/exception-handling.md | 303 +++++ .../pypi-pygls/docs/feature-registration.md | 308 +++++ .tessl/tiles/tessl/pypi-pygls/docs/index.md | 264 ++++ .../pypi-pygls/docs/progress-reporting.md | 546 ++++++++ .../pypi-pygls/docs/protocol-handling.md | 341 +++++ .../pypi-pygls/docs/server-management.md | 409 ++++++ .../tessl/pypi-pygls/docs/uri-utilities.md | 201 +++ .../tiles/tessl/pypi-pygls/docs/utilities.md | 442 +++++++ .../pypi-pygls/docs/workspace-management.md | 527 ++++++++ .tessl/tiles/tessl/pypi-pygls/tile.json | 7 + .../pypi-pytest-cov/docs/command-line.md | 237 ++++ .../docs/coverage-controllers.md | 363 +++++ .../pypi-pytest-cov/docs/error-handling.md | 342 +++++ .../pypi-pytest-cov/docs/fixtures-markers.md | 295 +++++ .../tiles/tessl/pypi-pytest-cov/docs/index.md | 216 +++ .../docs/plugin-integration.md | 298 +++++ .../docs/subprocess-support.md | 288 ++++ .tessl/tiles/tessl/pypi-pytest-cov/tile.json | 7 + .../tessl/pypi-pytest/docs/assertions.md | 280 ++++ .../tessl/pypi-pytest/docs/configuration.md | 460 +++++++ .../tiles/tessl/pypi-pytest/docs/fixtures.md | 311 +++++ .tessl/tiles/tessl/pypi-pytest/docs/index.md | 466 +++++++ .tessl/tiles/tessl/pypi-pytest/docs/marks.md | 364 +++++ .../tiles/tessl/pypi-pytest/docs/reporting.md | 538 ++++++++ .../tessl/pypi-pytest/docs/test-collection.md | 528 ++++++++ .../tessl/pypi-pytest/docs/test-utilities.md | 219 ++++ .../pypi-pytest/docs/testing-functions.md | 189 +++ .../tiles/tessl/pypi-pytest/docs/warnings.md | 341 +++++ .tessl/tiles/tessl/pypi-pytest/tile.json | 7 + .../tessl/pypi-requests/docs/adapters.md | 571 ++++++++ .../pypi-requests/docs/authentication.md | 344 +++++ .../tiles/tessl/pypi-requests/docs/cookies.md | 398 ++++++ .../tessl/pypi-requests/docs/exceptions.md | 430 ++++++ .../tiles/tessl/pypi-requests/docs/hooks.md | 471 +++++++ .../tessl/pypi-requests/docs/http-methods.md | 229 ++++ .../tiles/tessl/pypi-requests/docs/index.md | 262 ++++ .../tiles/tessl/pypi-requests/docs/models.md | 378 ++++++ .../tessl/pypi-requests/docs/sessions.md | 259 ++++ .../tessl/pypi-requests/docs/status-codes.md | 373 ++++++ .../tessl/pypi-requests/docs/structures.md | 457 +++++++ .tessl/tiles/tessl/pypi-requests/tile.json | 7 + .tessl/tiles/tessl/pypi-rich/docs/console.md | 494 +++++++ .../tiles/tessl/pypi-rich/docs/containers.md | 120 ++ .tessl/tiles/tessl/pypi-rich/docs/index.md | 592 +++++++++ .../tiles/tessl/pypi-rich/docs/interactive.md | 587 +++++++++ .tessl/tiles/tessl/pypi-rich/docs/layout.md | 113 ++ .tessl/tiles/tessl/pypi-rich/docs/markdown.md | 65 + .tessl/tiles/tessl/pypi-rich/docs/progress.md | 608 +++++++++ .tessl/tiles/tessl/pypi-rich/docs/syntax.md | 411 ++++++ .tessl/tiles/tessl/pypi-rich/docs/tables.md | 378 ++++++ .../tessl/pypi-rich/docs/text-styling.md | 739 +++++++++++ .../tiles/tessl/pypi-rich/docs/utilities.md | 74 ++ .tessl/tiles/tessl/pypi-rich/tile.json | 7 + .../pypi-sentry-sdk/docs/ai-monitoring.md | 231 ++++ .../pypi-sentry-sdk/docs/configuration.md | 162 +++ .../pypi-sentry-sdk/docs/context-metadata.md | 419 ++++++ .../pypi-sentry-sdk/docs/cron-monitoring.md | 425 ++++++ .../pypi-sentry-sdk/docs/event-capture.md | 244 ++++ .../tiles/tessl/pypi-sentry-sdk/docs/index.md | 331 +++++ .../pypi-sentry-sdk/docs/integrations.md | 480 +++++++ .../docs/performance-monitoring.md | 446 +++++++ .../tessl/pypi-sentry-sdk/docs/profiling.md | 427 ++++++ .../pypi-sentry-sdk/docs/scope-management.md | 321 +++++ .../docs/structured-logging.md | 363 +++++ .tessl/tiles/tessl/pypi-sentry-sdk/tile.json | 7 + .../tessl/pypi-tomlkit/docs/advanced-types.md | 345 +++++ .../pypi-tomlkit/docs/document-operations.md | 189 +++ .../tessl/pypi-tomlkit/docs/error-handling.md | 425 ++++++ .../pypi-tomlkit/docs/file-operations.md | 335 +++++ .tessl/tiles/tessl/pypi-tomlkit/docs/index.md | 186 +++ .../tessl/pypi-tomlkit/docs/item-classes.md | 509 +++++++ .../tessl/pypi-tomlkit/docs/item-creation.md | 288 ++++ .tessl/tiles/tessl/pypi-tomlkit/tile.json | 7 + .../docs/incremental-parsing.md | 389 ++++++ .../tessl/pypi-tree-sitter/docs/index.md | 260 ++++ .../pypi-tree-sitter/docs/language-parser.md | 359 +++++ .../tessl/pypi-tree-sitter/docs/queries.md | 490 +++++++ .../pypi-tree-sitter/docs/tree-navigation.md | 599 +++++++++ .tessl/tiles/tessl/pypi-tree-sitter/tile.json | 7 + .../tessl/pypi-uv/docs/authentication.md | 368 ++++++ .../tiles/tessl/pypi-uv/docs/build-system.md | 431 ++++++ .../tessl/pypi-uv/docs/cache-management.md | 393 ++++++ .tessl/tiles/tessl/pypi-uv/docs/index.md | 252 ++++ .../tiles/tessl/pypi-uv/docs/pip-interface.md | 428 ++++++ .../tessl/pypi-uv/docs/project-management.md | 471 +++++++ .../tessl/pypi-uv/docs/python-management.md | 303 +++++ .../tessl/pypi-uv/docs/self-management.md | 376 ++++++ .../tessl/pypi-uv/docs/tool-management.md | 372 ++++++ .../pypi-uv/docs/virtual-environments.md | 309 +++++ .tessl/tiles/tessl/pypi-uv/tile.json | 7 + tessl.json | 117 ++ 318 files changed, 107056 insertions(+) create mode 100644 .github/workflows/tessl-update.yml create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/annotations.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/configuration.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/index.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/json-tree-model.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/object-serialization.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/streaming-api.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/type-adapters.md create mode 100644 .tessl/tiles/tessl/maven-com-google-code-gson--gson/tile.json create mode 100644 .tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/docs/index.md create mode 100644 .tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/tile.json create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/assertions.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/conditional-execution.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/core-testing.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/dynamic-tests.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/extensions.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/index.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parallel-execution.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parameterized-tests.md create mode 100644 .tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/tile.json create mode 100644 .tessl/tiles/tessl/npm-babel--core/docs/configuration.md create mode 100644 .tessl/tiles/tessl/npm-babel--core/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-babel--core/docs/parsing.md create mode 100644 .tessl/tiles/tessl/npm-babel--core/docs/transformation.md create mode 100644 .tessl/tiles/tessl/npm-babel--core/docs/utilities.md create mode 100644 .tessl/tiles/tessl/npm-babel--core/tile.json create mode 100644 .tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-babel--preset-typescript/tile.json create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/database-management.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/statement-execution.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/transaction-management.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/docs/user-defined-functions.md create mode 100644 .tessl/tiles/tessl/npm-better-sqlite3/tile.json create mode 100644 .tessl/tiles/tessl/npm-jest/docs/cli-usage.md create mode 100644 .tessl/tiles/tessl/npm-jest/docs/configuration.md create mode 100644 .tessl/tiles/tessl/npm-jest/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-jest/docs/test-discovery.md create mode 100644 .tessl/tiles/tessl/npm-jest/docs/test-runner.md create mode 100644 .tessl/tiles/tessl/npm-jest/docs/test-scheduling.md create mode 100644 .tessl/tiles/tessl/npm-jest/tile.json create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/browser.md create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/cli-config.md create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/execution.md create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/interfaces.md create mode 100644 .tessl/tiles/tessl/npm-mocha/docs/reporters.md create mode 100644 .tessl/tiles/tessl/npm-mocha/tile.json create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/ast/factory.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/ast/nodes.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/ast/scanner-parser.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/ast/type-guards.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/core/compilation.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/core/config.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/core/module-resolution.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/core/solution-builder.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/api.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/completions.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/formatting.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/navigation.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/refactorings.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/language-service/tsserver.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/transformation/context.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/transformation/emit-helpers.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/transformation/transformers.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/types/diagnostics.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/types/type-checker.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/types/types-symbols.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/types/utilities.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/utilities/paths.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/utilities/printer.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/utilities/system.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/utilities/text.md create mode 100644 .tessl/tiles/tessl/npm-typescript/docs/utilities/transpilation.md create mode 100644 .tessl/tiles/tessl/npm-typescript/tile.json create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/assertions.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/benchmarking.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/browser-testing.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/configuration.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/index.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/mocking.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/node-apis.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/reporters.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/test-definition.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/timers.md create mode 100644 .tessl/tiles/tessl/npm-vitest/docs/type-testing.md create mode 100644 .tessl/tiles/tessl/npm-vitest/tile.json create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/class-definition.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/configuration-errors.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/field-configuration.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/utilities.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/docs/validation-conversion.md create mode 100644 .tessl/tiles/tessl/pypi-attrs/tile.json create mode 100644 .tessl/tiles/tessl/pypi-click/docs/command-definition.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/core-classes.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/exception-handling.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/parameter-types.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/terminal-ui.md create mode 100644 .tessl/tiles/tessl/pypi-click/docs/utilities.md create mode 100644 .tessl/tiles/tessl/pypi-click/tile.json create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/core-coverage.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/data-storage.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/exceptions.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/plugins.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/docs/reporting.md create mode 100644 .tessl/tiles/tessl/pypi-coverage/tile.json create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/docs/behavioral-analysis.md create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/docs/cli-tools.md create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/docs/contract-system.md create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/docs/symbolic-execution.md create mode 100644 .tessl/tiles/tessl/pypi-crosshair-tool/tile.json create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/core-serialization.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/diagnostic-tools.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/pickler-classes.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/session-management.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/source-analysis.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/temp-operations.md create mode 100644 .tessl/tiles/tessl/pypi-dill/docs/type-registry.md create mode 100644 .tessl/tiles/tessl/pypi-dill/tile.json create mode 100644 .tessl/tiles/tessl/pypi-filelock/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-filelock/tile.json create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/command.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/database.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/diff.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/exceptions.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/index-staging.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/objects.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/references.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/remote.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/docs/repository.md create mode 100644 .tessl/tiles/tessl/pypi-gitpython/tile.json create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/filesize-formatting.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/internationalization.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/list-formatting.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/number-formatting.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/docs/time-formatting.md create mode 100644 .tessl/tiles/tessl/pypi-humanize/tile.json create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/prompt-system.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/question-types.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/render-system.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/shortcuts.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/docs/themes.md create mode 100644 .tessl/tiles/tessl/pypi-inquirer/tile.json create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/code-navigation.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/code-refactoring.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/environment-management.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/interpreter-integration.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/project-configuration.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/docs/script-analysis.md create mode 100644 .tessl/tiles/tessl/pypi-jedi/tile.json create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/cli-tool.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/codemods.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/matchers.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/metadata.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/nodes.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/parsing.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/utilities.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/docs/visitors.md create mode 100644 .tessl/tiles/tessl/pypi-libcst/tile.json create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/etree-core.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/html-processing.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/objectify-api.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/utility-modules.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/validation.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/docs/xpath-xslt.md create mode 100644 .tessl/tiles/tessl/pypi-lxml/tile.json create mode 100644 .tessl/tiles/tessl/pypi-memray/docs/cli-commands.md create mode 100644 .tessl/tiles/tessl/pypi-memray/docs/file-io.md create mode 100644 .tessl/tiles/tessl/pypi-memray/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-memray/docs/ipython-integration.md create mode 100644 .tessl/tiles/tessl/pypi-memray/docs/memory-tracking.md create mode 100644 .tessl/tiles/tessl/pypi-memray/tile.json create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/ast-nodes.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/build-system.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/command-line-tools.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/daemon-mode.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/error-system.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/mypyc-compiler.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/plugin-system.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/programmatic-api.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/stub-tools.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/docs/type-system.md create mode 100644 .tessl/tiles/tessl/pypi-mypy/tile.json create mode 100644 .tessl/tiles/tessl/pypi-parameterized/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-parameterized/tile.json create mode 100644 .tessl/tiles/tessl/pypi-platformdirs/docs/functional-api.md create mode 100644 .tessl/tiles/tessl/pypi-platformdirs/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-platformdirs/docs/object-oriented-api.md create mode 100644 .tessl/tiles/tessl/pypi-platformdirs/docs/user-media-directories.md create mode 100644 .tessl/tiles/tessl/pypi-platformdirs/tile.json create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/ai-integrations.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/client-management.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/context-management.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/event-tracking.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/feature-flags.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/docs/user-group-management.md create mode 100644 .tessl/tiles/tessl/pypi-posthog/tile.json create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/core-models.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/dataclasses-adapters.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/error-handling.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/json-schema.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/plugins.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/serialization-config.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/type-system.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/docs/validation-system.md create mode 100644 .tessl/tiles/tessl/pypi-pydantic/tile.json create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/client-operations.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/exception-handling.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/feature-registration.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/progress-reporting.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/protocol-handling.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/server-management.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/uri-utilities.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/utilities.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/docs/workspace-management.md create mode 100644 .tessl/tiles/tessl/pypi-pygls/tile.json create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/command-line.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/coverage-controllers.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/error-handling.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/fixtures-markers.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/plugin-integration.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/docs/subprocess-support.md create mode 100644 .tessl/tiles/tessl/pypi-pytest-cov/tile.json create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/assertions.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/fixtures.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/marks.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/reporting.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/test-collection.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/test-utilities.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/testing-functions.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/docs/warnings.md create mode 100644 .tessl/tiles/tessl/pypi-pytest/tile.json create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/adapters.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/authentication.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/cookies.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/exceptions.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/hooks.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/http-methods.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/models.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/sessions.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/status-codes.md create mode 100644 .tessl/tiles/tessl/pypi-requests/docs/structures.md create mode 100644 .tessl/tiles/tessl/pypi-requests/tile.json create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/console.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/containers.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/interactive.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/layout.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/markdown.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/progress.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/syntax.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/tables.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/text-styling.md create mode 100644 .tessl/tiles/tessl/pypi-rich/docs/utilities.md create mode 100644 .tessl/tiles/tessl/pypi-rich/tile.json create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/ai-monitoring.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/configuration.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/context-metadata.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/cron-monitoring.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/event-capture.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/integrations.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/performance-monitoring.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/profiling.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/scope-management.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/docs/structured-logging.md create mode 100644 .tessl/tiles/tessl/pypi-sentry-sdk/tile.json create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/advanced-types.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/document-operations.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/error-handling.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/file-operations.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/item-classes.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/docs/item-creation.md create mode 100644 .tessl/tiles/tessl/pypi-tomlkit/tile.json create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/docs/incremental-parsing.md create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/docs/language-parser.md create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/docs/queries.md create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/docs/tree-navigation.md create mode 100644 .tessl/tiles/tessl/pypi-tree-sitter/tile.json create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/authentication.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/build-system.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/cache-management.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/index.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/pip-interface.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/project-management.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/python-management.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/self-management.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/tool-management.md create mode 100644 .tessl/tiles/tessl/pypi-uv/docs/virtual-environments.md create mode 100644 .tessl/tiles/tessl/pypi-uv/tile.json create mode 100644 tessl.json diff --git a/.github/workflows/tessl-update.yml b/.github/workflows/tessl-update.yml new file mode 100644 index 000000000..f9fb5e23e --- /dev/null +++ b/.github/workflows/tessl-update.yml @@ -0,0 +1,97 @@ +name: Tessl Tile Updates + +on: + schedule: + - cron: "0 9 * * 1" # Weekly on Monday at 9am UTC + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-tiles: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: tesslio/setup-tessl@v2 + with: + token: ${{ secrets.TESSL_TOKEN }} + + - name: Update existing tiles + run: tessl update --yes + + - name: Attempt to install missing tiles + run: | + workflow_file=".github/workflows/tessl-update.yml" + missing_tiles=( + tessl/pypi-tree-sitter-javascript + tessl/pypi-tree-sitter-typescript + tessl/pypi-tree-sitter-java + tessl/pypi-tree-sitter-groovy + tessl/pypi-tree-sitter-kotlin + tessl/pypi-pytest-timeout + tessl/pypi-junitparser + tessl/pypi-isort + tessl/pypi-line-profiler + tessl/pypi-pytest-asyncio + tessl/pypi-pytest-memray + tessl/pypi-unidiff + tessl/pypi-ruff + tessl/npm-msgpack--msgpack + tessl/npm-babel--register + tessl/npm-babel--preset-env + tessl/maven-com-esotericsoftware--kryo + tessl/maven-org-objenesis--objenesis + tessl/maven-org-xerial--sqlite-jdbc + tessl/maven-org-ow2-asm--asm + tessl/maven-org-ow2-asm--asm-commons + ) + installed=() + for tile in "${missing_tiles[@]}"; do + if tessl install --yes "$tile" 2>&1; then + installed+=("$tile") + fi + done + for tile in "${installed[@]}"; do + escaped=$(printf '%s\n' "$tile" | sed 's/[/]/\\\//g') + sed -i "/^ ${escaped}$/d" "$workflow_file" + done + if [ ${#installed[@]} -eq ${#missing_tiles[@]} ]; then + sed -i '/^ - name: Attempt to install missing tiles$/,/^ - name:/{ /^ - name: Attempt to install missing tiles$/,/^ - name: Check/{ /^ - name: Check/!d; }; }' "$workflow_file" || true + fi + + - name: Check for changes + id: changes + run: | + if git diff --quiet && git diff --cached --quiet; then + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + - name: Create PR with updates + if: steps.changes.outputs.changed == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + branch="chore/tessl-tile-updates-$(date +%Y%m%d)" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$branch" + git add tessl.json .tessl/tiles/ .github/workflows/tessl-update.yml + git commit -m "chore: update tessl tiles $(date +%Y-%m-%d)" + git push origin "$branch" + gh pr create \ + --title "chore: update tessl tiles $(date +%Y-%m-%d)" \ + --body "$(cat <<'EOF' + ## Summary + + Automated weekly tessl tile update: + - Updated existing tiles to latest versions + - Installed newly available tiles for project dependencies + + Generated by the **tessl-update** workflow. + EOF + )" diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/annotations.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/annotations.md new file mode 100644 index 000000000..7fcfa002f --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/annotations.md @@ -0,0 +1,405 @@ +# Annotations + +Gson provides several annotations to control serialization and deserialization behavior directly on fields and classes without requiring configuration changes. + +## @SerializedName + +Specifies alternative names for fields during serialization and deserialization. + +```java { .api } +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SerializedName { + String value(); + String[] alternate() default {}; +} +``` + +**Basic usage:** +```java +public class Person { + @SerializedName("full_name") + private String name; + + @SerializedName("years_old") + private int age; +} + +// JSON: {"full_name":"Alice","years_old":30} +``` + +**Multiple alternative names for deserialization:** +```java +public class Person { + @SerializedName(value = "name", alternate = {"full_name", "firstName", "first_name"}) + private String name; +} + +// Can deserialize from any of these JSON formats: +// {"name":"Alice"} +// {"full_name":"Alice"} +// {"firstName":"Alice"} +// {"first_name":"Alice"} +``` + +## @Expose + +Controls which fields are included in serialization and deserialization when using `excludeFieldsWithoutExposeAnnotation()`. + +```java { .api } +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Expose { + boolean serialize() default true; + boolean deserialize() default true; +} +``` + +**Usage:** +```java +public class User { + @Expose + private String name; + + @Expose(serialize = false) // Only for deserialization + private String password; + + @Expose(deserialize = false) // Only for serialization + private String token; + + private String internalId; // Not exposed +} + +Gson gson = new GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .create(); + +// Only fields marked with @Expose will be processed +``` + +## @Since + +Marks fields as available since a specific API version. + +```java { .api } +@Target({ElementType.FIELD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Since { + double value(); +} +``` + +**Usage:** +```java +public class ApiResponse { + private String status; + + @Since(1.1) + private String message; + + @Since(2.0) + private List errors; +} + +// Only include fields from version 1.1 and later +Gson gson = new GsonBuilder() + .setVersion(1.1) + .create(); + +// 'status' and 'message' will be included, but 'errors' will be excluded +``` + +## @Until + +Marks fields as available until a specific API version. + +```java { .api } +@Target({ElementType.FIELD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Until { + double value(); +} +``` + +**Usage:** +```java +public class LegacyResponse { + private String data; + + @Until(2.0) + private String oldFormat; // Deprecated in version 2.0 + + @Since(2.0) + private String newFormat; // Added in version 2.0 +} + +// Version 1.5: includes 'data' and 'oldFormat' +Gson gson15 = new GsonBuilder().setVersion(1.5).create(); + +// Version 2.1: includes 'data' and 'newFormat' +Gson gson21 = new GsonBuilder().setVersion(2.1).create(); +``` + +## @JsonAdapter + +Specifies a custom TypeAdapter, JsonSerializer, JsonDeserializer, or TypeAdapterFactory for a field or class. + +```java { .api } +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface JsonAdapter { + Class value(); + boolean nullSafe() default true; +} +``` + +**Field-level adapter:** +```java +public class Event { + private String name; + + @JsonAdapter(DateAdapter.class) + private Date timestamp; +} + +public class DateAdapter extends TypeAdapter { + private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(format.format(date)); + } + } + + @Override + public Date read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + try { + return format.parse(in.nextString()); + } catch (ParseException e) { + throw new IOException(e); + } + } +} +``` + +**Class-level adapter:** +```java +@JsonAdapter(ColorAdapter.class) +public class Color { + private int red, green, blue; + + public Color(int red, int green, int blue) { + this.red = red; + this.green = green; + this.blue = blue; + } +} + +public class ColorAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, Color color) throws IOException { + if (color == null) { + out.nullValue(); + } else { + String hex = String.format("#%02x%02x%02x", color.red, color.green, color.blue); + out.value(hex); + } + } + + @Override + public Color read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + String hex = in.nextString(); + if (hex.startsWith("#")) { + hex = hex.substring(1); + } + + int rgb = Integer.parseInt(hex, 16); + return new Color((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF); + } +} + +// Usage: Color serializes as "#ff0000" instead of {"red":255,"green":0,"blue":0} +``` + +**Using with JsonSerializer/JsonDeserializer:** +```java +public class User { + private String name; + + @JsonAdapter(PasswordSerializer.class) + private String password; +} + +public class PasswordSerializer implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive("***"); // Always serialize as stars + } + + @Override + public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + return json.getAsString(); // Deserialize normally + } +} +``` + +**Using with TypeAdapterFactory:** +```java +@JsonAdapter(CaseInsensitiveEnumAdapterFactory.class) +public enum Status { + ACTIVE, INACTIVE, PENDING +} + +public class CaseInsensitiveEnumAdapterFactory implements TypeAdapterFactory { + @Override + @SuppressWarnings("unchecked") + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!rawType.isEnum()) { + return null; + } + + return new TypeAdapter() { + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.toString()); + } + } + + @Override + @SuppressWarnings("unchecked") + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + String value = in.nextString().toUpperCase(); + return (T) Enum.valueOf((Class) rawType, value); + } + }; + } +} +``` + +## Combining Annotations + +Annotations can be combined for comprehensive control: + +```java +public class Product { + @SerializedName("product_id") + @Since(1.0) + private String id; + + @SerializedName("product_name") + @Expose + private String name; + + @SerializedName("price_cents") + @JsonAdapter(MoneyAdapter.class) + private Money price; + + @Until(2.0) + private String oldCategory; + + @Since(2.0) + @SerializedName("category_info") + private Category category; + + @Expose(serialize = false) + private String internalNotes; +} +``` + +## Annotation Processing Order + +Gson processes annotations in the following priority: + +1. **@JsonAdapter** - Takes highest precedence +2. **@SerializedName** - Controls field naming +3. **@Expose** - Controls field inclusion (when enabled) +4. **@Since/@Until** - Controls version-based inclusion +5. **Field modifiers** - Processed based on GsonBuilder configuration + +**Example:** +```java +public class Example { + @JsonAdapter(CustomAdapter.class) // 1. Custom adapter used + @SerializedName("custom_field") // 2. Field name in JSON + @Expose(serialize = false) // 3. Only deserialize (if expose filtering enabled) + @Since(1.1) // 4. Only if version >= 1.1 + private String field; +} +``` + +## Best Practices + +**Use @SerializedName for API compatibility:** +```java +public class ApiModel { + @SerializedName("user_id") + private String userId; // Java convention: camelCase + + @SerializedName("created_at") + private Date createdAt; // API uses snake_case +} +``` + +**Use @Expose for security:** +```java +public class User { + @Expose + private String username; + + @Expose + private String email; + + private String passwordHash; // Never expose sensitive data + + @Expose(serialize = false) + private String password; // Accept for input, never output +} +``` + +**Use versioning for API evolution:** +```java +public class ApiResponse { + private String status; + + @Until(1.9) + private String oldErrorMessage; + + @Since(2.0) + private ErrorDetails errorDetails; +} +``` + +**Use @JsonAdapter for domain-specific serialization:** +```java +public class Order { + @JsonAdapter(CurrencyAdapter.class) + private BigDecimal totalAmount; + + @JsonAdapter(TimestampAdapter.class) + private Instant orderTime; + + @JsonAdapter(Base64Adapter.class) + private byte[] signature; +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/configuration.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/configuration.md new file mode 100644 index 000000000..a42cd258f --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/configuration.md @@ -0,0 +1,357 @@ +# Configuration + +Gson provides extensive configuration options through the GsonBuilder class for customizing serialization and deserialization behavior. + +## GsonBuilder + +Builder pattern class for configuring Gson instances. + +```java { .api } +public final class GsonBuilder { + public GsonBuilder(); + + // JSON formatting + public GsonBuilder setPrettyPrinting(); + public GsonBuilder setFormattingStyle(FormattingStyle formattingStyle); + public GsonBuilder disableHtmlEscaping(); + + // Null handling + public GsonBuilder serializeNulls(); + + // Field naming + public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention); + public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy); + + // Version control + public GsonBuilder setVersion(double version); + + // Field exposure + public GsonBuilder excludeFieldsWithoutExposeAnnotation(); + public GsonBuilder excludeFieldsWithModifiers(int... modifiers); + + // Exclusion strategies + public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies); + public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy); + public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy); + + // Type adapters + public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter); + public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory); + public GsonBuilder registerTypeHierarchyAdapter(Class baseType, Object typeAdapter); + + // Number handling + public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy); + public GsonBuilder setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy); + public GsonBuilder setNumberToNumberStrategy(ToNumberStrategy numberToNumberStrategy); + public GsonBuilder serializeSpecialFloatingPointValues(); + + // Date formatting + public GsonBuilder setDateFormat(String pattern); + public GsonBuilder setDateFormat(int dateStyle); + public GsonBuilder setDateFormat(int dateStyle, int timeStyle); + + // JSON parsing strictness + public GsonBuilder setLenient(); + public GsonBuilder setStrictness(Strictness strictness); + + // Advanced options + public GsonBuilder enableComplexMapKeySerialization(); + public GsonBuilder disableInnerClassSerialization(); + public GsonBuilder generateNonExecutableJson(); + public GsonBuilder disableJdkUnsafe(); + public GsonBuilder addReflectionAccessFilter(ReflectionAccessFilter filter); + + // Build final instance + public Gson create(); +} +``` + +## Basic Configuration + +**Creating a configured Gson instance:** +```java +Gson gson = new GsonBuilder() + .setPrettyPrinting() + .serializeNulls() + .create(); +``` + +## Field Naming Policies + +Control how Java field names are converted to JSON property names. + +```java { .api } +public enum FieldNamingPolicy implements FieldNamingStrategy { + IDENTITY, + UPPER_CAMEL_CASE, + UPPER_CAMEL_CASE_WITH_SPACES, + UPPER_CASE_WITH_UNDERSCORES, + LOWER_CASE_WITH_UNDERSCORES, + LOWER_CASE_WITH_DASHES, + LOWER_CASE_WITH_DOTS +} +``` + +**Usage:** +```java +Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .create(); + +class Person { + String firstName; // becomes "first_name" in JSON + String lastName; // becomes "last_name" in JSON +} +``` + +## Custom Field Naming Strategy + +```java { .api } +public interface FieldNamingStrategy { + public String translateName(Field f); +} +``` + +**Usage:** +```java +FieldNamingStrategy customStrategy = field -> { + return "prefix_" + field.getName().toLowerCase(); +}; + +Gson gson = new GsonBuilder() + .setFieldNamingStrategy(customStrategy) + .create(); +``` + +## Exclusion Strategies + +Control which fields and classes are included in serialization/deserialization. + +```java { .api } +public interface ExclusionStrategy { + public boolean shouldSkipField(FieldAttributes f); + public boolean shouldSkipClass(Class clazz); +} +``` + +**Usage:** +```java +ExclusionStrategy strategy = new ExclusionStrategy() { + @Override + public boolean shouldSkipField(FieldAttributes f) { + return f.getName().startsWith("internal"); + } + + @Override + public boolean shouldSkipClass(Class clazz) { + return clazz.getName().contains("Internal"); + } +}; + +Gson gson = new GsonBuilder() + .setExclusionStrategies(strategy) + .create(); +``` + +## Field Attributes + +Information about fields for exclusion strategies. + +```java { .api } +public final class FieldAttributes { + public Class getDeclaringClass(); + public String getName(); + public Type getDeclaredType(); + public Class getDeclaredClass(); + public T getAnnotation(Class annotation); + public Collection getAnnotations(); + public boolean hasModifier(int modifier); +} +``` + +## Number Handling + +### Long Serialization Policy + +```java { .api } +public enum LongSerializationPolicy { + DEFAULT, // Serialize as numbers + STRING // Serialize as strings +} +``` + +**Usage:** +```java +Gson gson = new GsonBuilder() + .setLongSerializationPolicy(LongSerializationPolicy.STRING) + .create(); +``` + +### Number Strategies + +```java { .api } +public interface ToNumberStrategy { + public Number readNumber(JsonReader in) throws IOException; +} + +public enum ToNumberPolicy implements ToNumberStrategy { + DOUBLE, + LAZILY_PARSED_NUMBER, + LONG_OR_DOUBLE, + BIG_DECIMAL +} +``` + +**Usage:** +```java +Gson gson = new GsonBuilder() + .setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL) + .setNumberToNumberStrategy(ToNumberPolicy.BIG_DECIMAL) + .create(); +``` + +## Date Formatting + +**Pattern-based formatting:** +```java +Gson gson = new GsonBuilder() + .setDateFormat("yyyy-MM-dd HH:mm:ss") + .create(); +``` + +**Style-based formatting:** +```java +import java.text.DateFormat; + +Gson gson = new GsonBuilder() + .setDateFormat(DateFormat.LONG) + .create(); + +// Or with both date and time styles +Gson gson = new GsonBuilder() + .setDateFormat(DateFormat.MEDIUM, DateFormat.SHORT) + .create(); +``` + +## JSON Formatting + +### Pretty Printing + +```java +Gson gson = new GsonBuilder() + .setPrettyPrinting() + .create(); +``` + +### Custom Formatting Style + +```java { .api } +public class FormattingStyle { + public static FormattingStyle COMPACT; + public static FormattingStyle PRETTY; + + public FormattingStyle withNewline(String newline); + public FormattingStyle withIndent(String indent); + public FormattingStyle withSpaceAfterSeparators(boolean spaceAfterSeparators); +} +``` + +**Usage:** +```java +FormattingStyle style = FormattingStyle.PRETTY + .withIndent(" ") // 4 spaces + .withNewline("\n"); + +Gson gson = new GsonBuilder() + .setFormattingStyle(style) + .create(); +``` + +## Strictness Control + +```java { .api } +public enum Strictness { + LENIENT, // Allows malformed JSON + STRICT // Requires well-formed JSON +} +``` + +**Usage:** +```java +// Lenient parsing (allows single quotes, unquoted names, etc.) +Gson gson = new GsonBuilder() + .setLenient() + .create(); + +// Or explicitly set strictness +Gson gson = new GsonBuilder() + .setStrictness(Strictness.LENIENT) + .create(); +``` + +## Advanced Configuration + +### Complex Map Keys + +Enable serialization of complex objects as map keys: +```java +Gson gson = new GsonBuilder() + .enableComplexMapKeySerialization() + .create(); +``` + +### HTML Escaping + +Disable HTML character escaping: +```java +Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .create(); +``` + +### Reflection Access Control + +```java { .api } +public interface ReflectionAccessFilter { + enum FilterResult { ALLOW, BLOCK_INACCESSIBLE, BLOCK_ALL } + + FilterResult check(Class rawClass); +} +``` + +**Usage:** +```java +ReflectionAccessFilter filter = new ReflectionAccessFilter() { + @Override + public FilterResult check(Class rawClass) { + if (rawClass.getPackage().getName().startsWith("com.example.internal")) { + return FilterResult.BLOCK_ALL; + } + return FilterResult.ALLOW; + } +}; + +Gson gson = new GsonBuilder() + .addReflectionAccessFilter(filter) + .create(); +``` + +### Version Control + +Use `@Since` and `@Until` annotations with version setting: +```java +Gson gson = new GsonBuilder() + .setVersion(2.0) + .create(); +``` + +### Modifier-based Exclusion + +Exclude fields based on Java modifiers: +```java +import java.lang.reflect.Modifier; + +Gson gson = new GsonBuilder() + .excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT) + .create(); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/index.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/index.md new file mode 100644 index 000000000..00ba68e92 --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/index.md @@ -0,0 +1,211 @@ +# Gson + +Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code access to. + +## Package Information + +- **Package Name**: com.google.code.gson:gson +- **Package Type**: Maven +- **Language**: Java +- **Installation**: + ```xml + + com.google.code.gson + gson + 2.13.1 + + ``` + +## Core Imports + +```java +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +``` + +For JSON tree model: +```java +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonArray; +import com.google.gson.JsonPrimitive; +``` + +For streaming: +```java +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +``` + +## Basic Usage + +```java +import com.google.gson.Gson; + +// Simple object serialization +class Person { + private String name; + private int age; + + public Person(String name, int age) { + this.name = name; + this.age = age; + } +} + +// Create Gson instance +Gson gson = new Gson(); + +// Convert Java object to JSON +Person person = new Person("John", 30); +String json = gson.toJson(person); +// Result: {"name":"John","age":30} + +// Convert JSON to Java object +String jsonString = "{\"name\":\"Jane\",\"age\":25}"; +Person deserializedPerson = gson.fromJson(jsonString, Person.class); +``` + +## Architecture + +Gson is built around several key components: + +- **Gson Class**: Main entry point providing `toJson()` and `fromJson()` methods +- **GsonBuilder**: Builder pattern for configuring Gson instances with custom settings +- **JSON Tree Model**: Object representation (JsonElement hierarchy) for manipulating JSON as trees +- **Streaming API**: Memory-efficient reading/writing for large JSON documents +- **Type Adapters**: Pluggable serialization/deserialization for custom types +- **Reflection System**: Automatic object mapping using Java reflection + +## Capabilities + +### Object Serialization and Deserialization + +Core functionality for converting between Java objects and JSON strings. Handles arbitrarily complex objects with deep inheritance hierarchies and generic types. + +```java { .api } +public String toJson(Object src); +public String toJson(Object src, Type typeOfSrc); +public T fromJson(String json, Class classOfT); +public T fromJson(String json, Type typeOfT); +public T fromJson(String json, TypeToken typeOfT); +``` + +[Object Serialization](./object-serialization.md) + +### JSON Tree Model + +Tree-based API for building and manipulating JSON structures programmatically. Useful when you need to modify JSON before serialization or after deserialization. + +```java { .api } +public JsonElement toJsonTree(Object src); +public T fromJson(JsonElement json, Class classOfT); + +abstract class JsonElement { + public boolean isJsonObject(); + public boolean isJsonArray(); + public boolean isJsonPrimitive(); + public boolean isJsonNull(); +} +``` + +[JSON Tree Model](./json-tree-model.md) + +### Configuration and Customization + +Extensive configuration options for controlling serialization behavior, field naming, date formatting, and custom type adapters. + +```java { .api } +public final class GsonBuilder { + public GsonBuilder setPrettyPrinting(); + public GsonBuilder serializeNulls(); + public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention); + public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter); + public Gson create(); +} +``` + +[Configuration](./configuration.md) + +### Streaming API + +Memory-efficient streaming API for processing large JSON documents without loading them entirely into memory. + +```java { .api } +public class JsonReader implements Closeable { + public JsonToken peek() throws IOException; + public String nextString() throws IOException; + public int nextInt() throws IOException; + public void beginObject() throws IOException; + public void endObject() throws IOException; +} + +public class JsonWriter implements Closeable, Flushable { + public JsonWriter name(String name) throws IOException; + public JsonWriter value(String value) throws IOException; + public JsonWriter beginObject() throws IOException; + public JsonWriter endObject() throws IOException; +} +``` + +[Streaming API](./streaming-api.md) + +### Type Adapters + +Pluggable system for custom serialization and deserialization logic. Allows fine-grained control over how specific types are converted. + +```java { .api } +public abstract class TypeAdapter { + public abstract void write(JsonWriter out, T value) throws IOException; + public abstract T read(JsonReader in) throws IOException; +} + +public interface TypeAdapterFactory { + public TypeAdapter create(Gson gson, TypeToken type); +} +``` + +[Type Adapters](./type-adapters.md) + +### Annotations + +Annotations for controlling serialization behavior on fields and classes without requiring configuration changes. + +```java { .api } +@SerializedName("custom_name") +@Expose(serialize = true, deserialize = true) +@Since(1.0) +@Until(2.0) +@JsonAdapter(CustomAdapter.class) +``` + +[Annotations](./annotations.md) + +## Types + +```java { .api } +// Core exception types +class JsonParseException extends RuntimeException {} +class JsonSyntaxException extends JsonParseException {} +class JsonIOException extends JsonParseException {} + +// Enums for configuration +enum FieldNamingPolicy { + IDENTITY, UPPER_CAMEL_CASE, UPPER_CAMEL_CASE_WITH_SPACES, + UPPER_CASE_WITH_UNDERSCORES, LOWER_CASE_WITH_UNDERSCORES, + LOWER_CASE_WITH_DASHES, LOWER_CASE_WITH_DOTS +} + +enum LongSerializationPolicy { DEFAULT, STRING } + +enum ToNumberPolicy implements ToNumberStrategy { + DOUBLE, LAZILY_PARSED_NUMBER, LONG_OR_DOUBLE, BIG_DECIMAL +} + +// Type handling +class TypeToken { + public static TypeToken get(Class type); + public static TypeToken get(Type type); + public Type getType(); +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/json-tree-model.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/json-tree-model.md new file mode 100644 index 000000000..7b662f48d --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/json-tree-model.md @@ -0,0 +1,317 @@ +# JSON Tree Model + +Gson provides a tree-based API for building and manipulating JSON structures programmatically. This is useful when you need to modify JSON before serialization or after deserialization. + +## JsonElement Hierarchy + +```java { .api } +public abstract class JsonElement { + public abstract JsonElement deepCopy(); + + // Type checking methods + public boolean isJsonArray(); + public boolean isJsonObject(); + public boolean isJsonPrimitive(); + public boolean isJsonNull(); + + // Conversion methods + public JsonObject getAsJsonObject(); + public JsonArray getAsJsonArray(); + public JsonPrimitive getAsJsonPrimitive(); + public JsonNull getAsJsonNull(); + + // Primitive value extraction + public boolean getAsBoolean(); + public Number getAsNumber(); + public String getAsString(); + public double getAsDouble(); + public float getAsFloat(); + public long getAsLong(); + public int getAsInt(); + public byte getAsByte(); + public char getAsCharacter(); +} +``` + +## JsonObject + +Represents JSON objects with key-value pairs. + +```java { .api } +public final class JsonObject extends JsonElement { + public JsonObject(); + public JsonObject deepCopy(); + + // Adding elements + public void add(String property, JsonElement value); + public void addProperty(String property, String value); + public void addProperty(String property, Number value); + public void addProperty(String property, Boolean value); + public void addProperty(String property, Character value); + + // Accessing elements + public JsonElement get(String memberName); + public JsonPrimitive getAsJsonPrimitive(String memberName); + public JsonArray getAsJsonArray(String memberName); + public JsonObject getAsJsonObject(String memberName); + + // Management + public JsonElement remove(String property); + public boolean has(String memberName); + public Set> entrySet(); + public Set keySet(); + public int size(); + public boolean isEmpty(); +} +``` + +**Usage:** +```java +// Create JSON object programmatically +JsonObject person = new JsonObject(); +person.addProperty("name", "Alice"); +person.addProperty("age", 30); +person.addProperty("active", true); + +// Convert to string +Gson gson = new Gson(); +String json = gson.toJson(person); +// Result: {"name":"Alice","age":30,"active":true} + +// Access properties +String name = person.get("name").getAsString(); +int age = person.get("age").getAsInt(); +boolean active = person.get("active").getAsBoolean(); + +// Check if property exists +if (person.has("email")) { + String email = person.get("email").getAsString(); +} +``` + +## JsonArray + +Represents JSON arrays. + +```java { .api } +public final class JsonArray extends JsonElement { + public JsonArray(); + public JsonArray(int capacity); + public JsonArray deepCopy(); + + // Adding elements + public void add(JsonElement element); + public void add(Boolean bool); + public void add(Character character); + public void add(Number number); + public void add(String string); + + // Accessing elements + public JsonElement get(int index); + + // Management + public JsonElement remove(int index); + public boolean remove(JsonElement element); + public boolean contains(JsonElement element); + public int size(); + public boolean isEmpty(); + + // Iteration + public Iterator iterator(); +} +``` + +**Usage:** +```java +// Create JSON array +JsonArray numbers = new JsonArray(); +numbers.add(1); +numbers.add(2); +numbers.add(3); + +// Convert to string +String json = gson.toJson(numbers); +// Result: [1,2,3] + +// Access elements +for (int i = 0; i < numbers.size(); i++) { + int value = numbers.get(i).getAsInt(); + System.out.println(value); +} + +// Using iterator +for (JsonElement element : numbers) { + int value = element.getAsInt(); + System.out.println(value); +} +``` + +## JsonPrimitive + +Represents JSON primitive values (strings, numbers, booleans). + +```java { .api } +public final class JsonPrimitive extends JsonElement { + public JsonPrimitive(Boolean bool); + public JsonPrimitive(Number number); + public JsonPrimitive(String string); + public JsonPrimitive(Character c); + public JsonPrimitive deepCopy(); + + public boolean isBoolean(); + public boolean isNumber(); + public boolean isString(); +} +``` + +**Usage:** +```java +JsonPrimitive stringValue = new JsonPrimitive("Hello"); +JsonPrimitive numberValue = new JsonPrimitive(42); +JsonPrimitive boolValue = new JsonPrimitive(true); + +// Check types +if (stringValue.isString()) { + String str = stringValue.getAsString(); +} + +if (numberValue.isNumber()) { + int num = numberValue.getAsInt(); + double dbl = numberValue.getAsDouble(); +} +``` + +## JsonNull + +Represents JSON null values. + +```java { .api } +public final class JsonNull extends JsonElement { + public static final JsonNull INSTANCE; + public JsonNull deepCopy(); +} +``` + +**Usage:** +```java +JsonObject obj = new JsonObject(); +obj.add("nullValue", JsonNull.INSTANCE); +``` + +## Tree Conversion + +Convert between objects and JSON trees: + +```java { .api } +// Object to tree +public JsonElement toJsonTree(Object src); +public JsonElement toJsonTree(Object src, Type typeOfSrc); + +// Tree to object +public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException; +public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException; +public T fromJson(JsonElement json, TypeToken typeOfT) throws JsonSyntaxException; +``` + +**Usage:** +```java +// Object to tree +Person person = new Person("Bob", 25); +JsonElement tree = gson.toJsonTree(person); + +// Modify the tree +JsonObject obj = tree.getAsJsonObject(); +obj.addProperty("email", "bob@example.com"); + +// Tree back to object +Person modifiedPerson = gson.fromJson(obj, Person.class); + +// Tree to JSON string +String json = gson.toJson(tree); +``` + +## JsonParser + +Utility for parsing JSON strings into JsonElement trees. + +```java { .api } +public final class JsonParser { + public static JsonElement parseString(String json) throws JsonSyntaxException; + public static JsonElement parseReader(Reader reader) throws JsonIOException, JsonSyntaxException; + public static JsonElement parseReader(JsonReader reader) throws JsonIOException, JsonSyntaxException; +} +``` + +**Usage:** +```java +String json = "{\"name\":\"Alice\",\"age\":30}"; +JsonElement element = JsonParser.parseString(json); + +if (element.isJsonObject()) { + JsonObject obj = element.getAsJsonObject(); + String name = obj.get("name").getAsString(); +} +``` + +## JsonStreamParser + +Streaming parser for processing multiple JSON values from a single reader. + +```java { .api } +public final class JsonStreamParser implements Iterator { + public JsonStreamParser(Reader reader); + public JsonStreamParser(String json); + + public boolean hasNext(); + public JsonElement next() throws JsonParseException; +} +``` + +**Usage:** +```java +String multipleJson = "{\"name\":\"Alice\"} {\"name\":\"Bob\"} [1,2,3]"; +JsonStreamParser parser = new JsonStreamParser(multipleJson); + +while (parser.hasNext()) { + JsonElement element = parser.next(); + System.out.println(element); +} +``` + +## Complex Tree Manipulation + +**Building nested structures:** +```java +JsonObject address = new JsonObject(); +address.addProperty("street", "123 Main St"); +address.addProperty("city", "Springfield"); + +JsonObject person = new JsonObject(); +person.addProperty("name", "John"); +person.add("address", address); + +JsonArray hobbies = new JsonArray(); +hobbies.add("reading"); +hobbies.add("swimming"); +person.add("hobbies", hobbies); +``` + +**Traversing complex structures:** +```java +JsonObject root = JsonParser.parseString(complexJson).getAsJsonObject(); + +for (Map.Entry entry : root.entrySet()) { + String key = entry.getKey(); + JsonElement value = entry.getValue(); + + if (value.isJsonObject()) { + JsonObject nested = value.getAsJsonObject(); + // Process nested object + } else if (value.isJsonArray()) { + JsonArray array = value.getAsJsonArray(); + for (JsonElement item : array) { + // Process array item + } + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/object-serialization.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/object-serialization.md new file mode 100644 index 000000000..fe70c5c0c --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/object-serialization.md @@ -0,0 +1,217 @@ +# Object Serialization + +The core functionality of Gson for converting between Java objects and JSON strings. + +## Serialization (Java to JSON) + +### Basic Serialization + +```java { .api } +public String toJson(Object src); +``` + +Converts any Java object to its JSON string representation using default settings. + +**Usage:** +```java +Gson gson = new Gson(); +Person person = new Person("Alice", 30); +String json = gson.toJson(person); +// Result: {"name":"Alice","age":30} +``` + +### Serialization with Type Information + +```java { .api } +public String toJson(Object src, Type typeOfSrc); +``` + +Explicitly specifies the type for serialization, useful for generic collections and inheritance hierarchies. + +**Usage:** +```java +List names = Arrays.asList("Alice", "Bob", "Charlie"); +Type listType = new TypeToken>(){}.getType(); +String json = gson.toJson(names, listType); +// Result: ["Alice","Bob","Charlie"] +``` + +### Serialization to Writer + +```java { .api } +public void toJson(Object src, Appendable writer) throws JsonIOException; +public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException; +public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException; +``` + +Serialize directly to a Writer or JsonWriter for memory efficiency or streaming output. + +**Usage:** +```java +StringWriter writer = new StringWriter(); +gson.toJson(person, writer); +String json = writer.toString(); +``` + +## Deserialization (JSON to Java) + +### Basic Deserialization + +```java { .api } +public T fromJson(String json, Class classOfT) throws JsonSyntaxException; +``` + +Converts JSON string to Java object of the specified class. + +**Usage:** +```java +String json = "{\"name\":\"Bob\",\"age\":25}"; +Person person = gson.fromJson(json, Person.class); +``` + +### Deserialization with Generic Types + +```java { .api } +public T fromJson(String json, Type typeOfT) throws JsonSyntaxException; +public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxException; +``` + +Handles generic types like collections and maps using Type or TypeToken. + +**Usage:** +```java +String json = "[\"Alice\",\"Bob\",\"Charlie\"]"; +Type listType = new TypeToken>(){}.getType(); +List names = gson.fromJson(json, listType); + +// Or using TypeToken directly +TypeToken> token = new TypeToken>(){}; +List names = gson.fromJson(json, token); +``` + +### Deserialization from Reader + +```java { .api } +public T fromJson(Reader json, Class classOfT) throws JsonIOException, JsonSyntaxException; +public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException; +public T fromJson(Reader json, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException; +``` + +Deserialize from a Reader for memory-efficient processing of large files. + +**Usage:** +```java +FileReader reader = new FileReader("data.json"); +Person person = gson.fromJson(reader, Person.class); +reader.close(); +``` + +### Deserialization from JsonReader + +```java { .api } +public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException; +public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException; +``` + +Deserialize from JsonReader for streaming API integration. + +**Usage:** +```java +JsonReader reader = new JsonReader(new StringReader(json)); +Person person = gson.fromJson(reader, Person.class); +reader.close(); +``` + +## Complex Object Handling + +### Collections + +Gson automatically handles standard Java collections: + +```java +// Lists +List list = Arrays.asList("a", "b", "c"); +String json = gson.toJson(list); +List restored = gson.fromJson(json, new TypeToken>(){}.getType()); + +// Maps +Map map = new HashMap<>(); +map.put("one", 1); +map.put("two", 2); +String json = gson.toJson(map); +Map restored = gson.fromJson(json, new TypeToken>(){}.getType()); +``` + +### Arrays + +```java +int[] numbers = {1, 2, 3, 4, 5}; +String json = gson.toJson(numbers); +int[] restored = gson.fromJson(json, int[].class); +``` + +### Nested Objects + +```java +class Address { + String street; + String city; +} + +class Person { + String name; + Address address; +} + +Person person = new Person(); +person.name = "John"; +person.address = new Address(); +person.address.street = "123 Main St"; +person.address.city = "Springfield"; + +String json = gson.toJson(person); +Person restored = gson.fromJson(json, Person.class); +``` + +### Inheritance + +```java +class Animal { + String name; +} + +class Dog extends Animal { + String breed; +} + +Dog dog = new Dog(); +dog.name = "Buddy"; +dog.breed = "Golden Retriever"; + +// Serialize as Dog type +String json = gson.toJson(dog, Dog.class); +Dog restored = gson.fromJson(json, Dog.class); +``` + +## Error Handling + +```java { .api } +class JsonSyntaxException extends JsonParseException { + // Thrown when JSON syntax is invalid +} + +class JsonIOException extends JsonParseException { + // Thrown when I/O errors occur during reading/writing +} +``` + +**Usage:** +```java +try { + Person person = gson.fromJson(invalidJson, Person.class); +} catch (JsonSyntaxException e) { + System.err.println("Invalid JSON syntax: " + e.getMessage()); +} catch (JsonIOException e) { + System.err.println("I/O error: " + e.getMessage()); +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/streaming-api.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/streaming-api.md new file mode 100644 index 000000000..5a4f870e9 --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/streaming-api.md @@ -0,0 +1,396 @@ +# Streaming API + +Gson's streaming API provides memory-efficient processing of JSON data through JsonReader and JsonWriter classes. This is essential for handling large JSON documents without loading them entirely into memory. + +## JsonReader + +Read JSON content in a streaming fashion. + +```java { .api } +public class JsonReader implements Closeable { + public JsonReader(Reader in); + + // Configuration + public void setLenient(boolean lenient); + public boolean isLenient(); + public void setStrictness(Strictness strictness); + public Strictness getStrictness(); + + // Navigation + public JsonToken peek() throws IOException; + public JsonToken nextToken() throws IOException; + public void skipValue() throws IOException; + + // Object navigation + public void beginObject() throws IOException; + public void endObject() throws IOException; + public String nextName() throws IOException; + + // Array navigation + public void beginArray() throws IOException; + public void endArray() throws IOException; + + // Value reading + public String nextString() throws IOException; + public boolean nextBoolean() throws IOException; + public void nextNull() throws IOException; + public double nextDouble() throws IOException; + public long nextLong() throws IOException; + public int nextInt() throws IOException; + + // State + public boolean hasNext() throws IOException; + public String getPath(); + + // Resource management + public void close() throws IOException; +} +``` + +### JsonToken Enum + +```java { .api } +public enum JsonToken { + BEGIN_ARRAY, + END_ARRAY, + BEGIN_OBJECT, + END_OBJECT, + NAME, + STRING, + NUMBER, + BOOLEAN, + NULL, + END_DOCUMENT +} +``` + +**Reading JSON objects:** +```java +String json = "{\"name\":\"Alice\",\"age\":30,\"active\":true}"; +JsonReader reader = new JsonReader(new StringReader(json)); + +reader.beginObject(); +while (reader.hasNext()) { + String name = reader.nextName(); + switch (name) { + case "name": + String personName = reader.nextString(); + break; + case "age": + int age = reader.nextInt(); + break; + case "active": + boolean active = reader.nextBoolean(); + break; + default: + reader.skipValue(); // Skip unknown properties + break; + } +} +reader.endObject(); +reader.close(); +``` + +**Reading JSON arrays:** +```java +String json = "[1,2,3,4,5]"; +JsonReader reader = new JsonReader(new StringReader(json)); + +reader.beginArray(); +while (reader.hasNext()) { + int value = reader.nextInt(); + System.out.println(value); +} +reader.endArray(); +reader.close(); +``` + +**Reading complex nested structures:** +```java +String json = "{\"users\":[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]}"; +JsonReader reader = new JsonReader(new StringReader(json)); + +reader.beginObject(); +while (reader.hasNext()) { + String name = reader.nextName(); + if ("users".equals(name)) { + reader.beginArray(); + while (reader.hasNext()) { + reader.beginObject(); + String userName = null; + int age = 0; + while (reader.hasNext()) { + String fieldName = reader.nextName(); + if ("name".equals(fieldName)) { + userName = reader.nextString(); + } else if ("age".equals(fieldName)) { + age = reader.nextInt(); + } else { + reader.skipValue(); + } + } + reader.endObject(); + System.out.println("User: " + userName + ", Age: " + age); + } + reader.endArray(); + } else { + reader.skipValue(); + } +} +reader.endObject(); +reader.close(); +``` + +## JsonWriter + +Write JSON content in a streaming fashion. + +```java { .api } +public class JsonWriter implements Closeable, Flushable { + public JsonWriter(Writer out); + + // Configuration + public void setLenient(boolean lenient); + public boolean isLenient(); + public void setStrictness(Strictness strictness); + public Strictness getStrictness(); + public void setIndent(String indent); + public void setHtmlSafe(boolean htmlSafe); + public boolean isHtmlSafe(); + public void setSerializeNulls(boolean serializeNulls); + public boolean getSerializeNulls(); + + // Object writing + public JsonWriter beginObject() throws IOException; + public JsonWriter endObject() throws IOException; + public JsonWriter name(String name) throws IOException; + + // Array writing + public JsonWriter beginArray() throws IOException; + public JsonWriter endArray() throws IOException; + + // Value writing + public JsonWriter value(String value) throws IOException; + public JsonWriter nullValue() throws IOException; + public JsonWriter value(boolean value) throws IOException; + public JsonWriter value(Boolean value) throws IOException; + public JsonWriter value(double value) throws IOException; + public JsonWriter value(long value) throws IOException; + public JsonWriter value(Number value) throws IOException; + + // JSON value writing + public JsonWriter jsonValue(String value) throws IOException; + + // Resource management + public void flush() throws IOException; + public void close() throws IOException; +} +``` + +**Writing JSON objects:** +```java +StringWriter stringWriter = new StringWriter(); +JsonWriter writer = new JsonWriter(stringWriter); + +writer.beginObject(); +writer.name("name").value("Alice"); +writer.name("age").value(30); +writer.name("active").value(true); +writer.name("salary").nullValue(); +writer.endObject(); + +writer.close(); +String json = stringWriter.toString(); +// Result: {"name":"Alice","age":30,"active":true,"salary":null} +``` + +**Writing JSON arrays:** +```java +StringWriter stringWriter = new StringWriter(); +JsonWriter writer = new JsonWriter(stringWriter); + +writer.beginArray(); +writer.value(1); +writer.value(2); +writer.value(3); +writer.endArray(); + +writer.close(); +String json = stringWriter.toString(); +// Result: [1,2,3] +``` + +**Writing complex nested structures:** +```java +StringWriter stringWriter = new StringWriter(); +JsonWriter writer = new JsonWriter(stringWriter); + +writer.beginObject(); +writer.name("users"); +writer.beginArray(); + +writer.beginObject(); +writer.name("name").value("Alice"); +writer.name("age").value(30); +writer.name("hobbies"); +writer.beginArray(); +writer.value("reading"); +writer.value("swimming"); +writer.endArray(); +writer.endObject(); + +writer.beginObject(); +writer.name("name").value("Bob"); +writer.name("age").value(25); +writer.name("hobbies"); +writer.beginArray(); +writer.value("gaming"); +writer.endArray(); +writer.endObject(); + +writer.endArray(); +writer.endObject(); + +writer.close(); +``` + +## Gson Integration + +Create JsonReader and JsonWriter through Gson for consistent configuration: + +```java { .api } +public JsonWriter newJsonWriter(Writer writer) throws IOException; +public JsonReader newJsonReader(Reader reader); +``` + +**Usage:** +```java +Gson gson = new GsonBuilder() + .setPrettyPrinting() + .setLenient() + .create(); + +// Create configured writer +StringWriter stringWriter = new StringWriter(); +JsonWriter writer = gson.newJsonWriter(stringWriter); + +// Create configured reader +JsonReader reader = gson.newJsonReader(new StringReader(json)); +``` + +## Error Handling + +```java { .api } +class MalformedJsonException extends IOException { + // Thrown when JSON structure is invalid +} +``` + +**Error handling example:** +```java +try { + JsonReader reader = new JsonReader(new StringReader(malformedJson)); + reader.beginObject(); + // ... reading logic +} catch (MalformedJsonException e) { + System.err.println("Malformed JSON: " + e.getMessage()); +} catch (IOException e) { + System.err.println("I/O error: " + e.getMessage()); +} +``` + +## Advanced Usage + +### Lenient Mode + +Allow relaxed JSON syntax: +```java +JsonReader reader = new JsonReader(new StringReader(json)); +reader.setLenient(true); + +// Now can read: {name: 'Alice', age: 30} (unquoted names, single quotes) +``` + +### Pretty Printing + +Configure indentation for readable output: +```java +JsonWriter writer = new JsonWriter(new FileWriter("output.json")); +writer.setIndent(" "); // 2-space indentation + +writer.beginObject(); +writer.name("name").value("Alice"); +writer.name("details"); +writer.beginObject(); +writer.name("age").value(30); +writer.endObject(); +writer.endObject(); +``` + +### Large File Processing + +Process large JSON files efficiently: +```java +// Reading large file +try (FileReader fileReader = new FileReader("large-data.json"); + JsonReader reader = new JsonReader(fileReader)) { + + reader.beginArray(); + while (reader.hasNext()) { + // Process each object without loading entire file + processObject(reader); + } + reader.endArray(); +} + +private void processObject(JsonReader reader) throws IOException { + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + // Handle each field as needed + if ("data".equals(name)) { + // Process data field + } else { + reader.skipValue(); + } + } + reader.endObject(); +} +``` + +### Custom Adapter Integration + +Use streaming API within custom TypeAdapters: +```java +public class PersonAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, Person person) throws IOException { + out.beginObject(); + out.name("name").value(person.getName()); + out.name("age").value(person.getAge()); + out.endObject(); + } + + @Override + public Person read(JsonReader in) throws IOException { + Person person = new Person(); + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + switch (name) { + case "name": + person.setName(in.nextString()); + break; + case "age": + person.setAge(in.nextInt()); + break; + default: + in.skipValue(); + break; + } + } + in.endObject(); + return person; + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/type-adapters.md b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/type-adapters.md new file mode 100644 index 000000000..4a92ff92b --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/docs/type-adapters.md @@ -0,0 +1,393 @@ +# Type Adapters + +Type adapters provide fine-grained control over JSON serialization and deserialization for specific types. They are the most flexible way to customize Gson's behavior. + +## TypeAdapter Abstract Class + +The base class for all type adapters. + +```java { .api } +public abstract class TypeAdapter { + public abstract void write(JsonWriter out, T value) throws IOException; + public abstract T read(JsonReader in) throws IOException; + + // Convenience methods + public final String toJson(T value); + public final void toJson(Writer out, T value) throws IOException; + public final T fromJson(String json) throws IOException; + public final T fromJson(Reader in) throws IOException; + + // Null handling + public final TypeAdapter nullSafe(); +} +``` + +## Creating Custom Type Adapters + +**Basic type adapter example:** +```java +public class PersonAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, Person person) throws IOException { + if (person == null) { + out.nullValue(); + return; + } + + out.beginObject(); + out.name("name").value(person.getName()); + out.name("age").value(person.getAge()); + out.name("email").value(person.getEmail()); + out.endObject(); + } + + @Override + public Person read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + Person person = new Person(); + in.beginObject(); + while (in.hasNext()) { + String name = in.nextName(); + switch (name) { + case "name": + person.setName(in.nextString()); + break; + case "age": + person.setAge(in.nextInt()); + break; + case "email": + person.setEmail(in.nextString()); + break; + default: + in.skipValue(); // Skip unknown properties + break; + } + } + in.endObject(); + return person; + } +} +``` + +**Registering the adapter:** +```java +Gson gson = new GsonBuilder() + .registerTypeAdapter(Person.class, new PersonAdapter()) + .create(); + +Person person = new Person("Alice", 30, "alice@example.com"); +String json = gson.toJson(person); +Person restored = gson.fromJson(json, Person.class); +``` + +## TypeAdapterFactory Interface + +Factory pattern for creating type adapters dynamically. + +```java { .api } +public interface TypeAdapterFactory { + public TypeAdapter create(Gson gson, TypeToken type); +} +``` + +**Example factory for enum handling:** +```java +public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory { + @Override + @SuppressWarnings("unchecked") + public TypeAdapter create(Gson gson, TypeToken type) { + Class rawType = (Class) type.getRawType(); + if (!rawType.isEnum()) { + return null; // This factory only handles enums + } + + return new TypeAdapter() { + @Override + public void write(JsonWriter out, T value) throws IOException { + if (value == null) { + out.nullValue(); + } else { + out.value(value.toString().toLowerCase()); + } + } + + @Override + @SuppressWarnings("unchecked") + public T read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + String value = in.nextString().toUpperCase(); + return (T) Enum.valueOf((Class) rawType, value); + } + }; + } +} +``` + +**Registering the factory:** +```java +Gson gson = new GsonBuilder() + .registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory()) + .create(); +``` + +## Built-in Type Adapters + +Gson provides many built-in type adapters accessible through the TypeAdapters utility class. + +```java { .api } +public final class TypeAdapters { + public static final TypeAdapter CLASS; + public static final TypeAdapter BOOLEAN; + public static final TypeAdapter BOOLEAN_AS_STRING; + public static final TypeAdapter BYTE; + public static final TypeAdapter SHORT; + public static final TypeAdapter INTEGER; + public static final TypeAdapter ATOMIC_INTEGER; + public static final TypeAdapter ATOMIC_BOOLEAN; + public static final TypeAdapter LONG; + public static final TypeAdapter FLOAT; + public static final TypeAdapter DOUBLE; + public static final TypeAdapter CHARACTER; + public static final TypeAdapter STRING; + public static final TypeAdapter STRING_BUILDER; + public static final TypeAdapter STRING_BUFFER; + public static final TypeAdapter URL; + public static final TypeAdapter URI; + public static final TypeAdapter UUID; + public static final TypeAdapter CURRENCY; + public static final TypeAdapter CALENDAR; + public static final TypeAdapter LOCALE; + public static final TypeAdapter JSON_ELEMENT; + + // Factory methods + public static TypeAdapterFactory newFactory(Class type, TypeAdapter typeAdapter); + public static TypeAdapterFactory newFactory(TypeToken type, TypeAdapter typeAdapter); + public static TypeAdapterFactory newFactoryForMultipleTypes(Class base, Class sub, TypeAdapter typeAdapter); +} +``` + +## Advanced Type Adapter Patterns + +### Generic Type Handling + +```java +public class ListTypeAdapterFactory implements TypeAdapterFactory { + @Override + @SuppressWarnings("unchecked") + public TypeAdapter create(Gson gson, TypeToken type) { + Type rawType = type.getRawType(); + if (rawType != List.class) { + return null; + } + + Type elementType = ((ParameterizedType) type.getType()).getActualTypeArguments()[0]; + TypeAdapter elementAdapter = gson.getAdapter(TypeToken.get(elementType)); + + return (TypeAdapter) new TypeAdapter>() { + @Override + public void write(JsonWriter out, List list) throws IOException { + if (list == null) { + out.nullValue(); + return; + } + + out.beginArray(); + for (Object element : list) { + elementAdapter.write(out, element); + } + out.endArray(); + } + + @Override + public List read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + List list = new ArrayList<>(); + in.beginArray(); + while (in.hasNext()) { + list.add(elementAdapter.read(in)); + } + in.endArray(); + return list; + } + }; + } +} +``` + +### Delegating Adapters + +Sometimes you need to modify the behavior of an existing adapter: + +```java +public class TimestampAdapter extends TypeAdapter { + private final TypeAdapter delegate; + + public TimestampAdapter(TypeAdapter delegate) { + this.delegate = delegate; + } + + @Override + public void write(JsonWriter out, Date date) throws IOException { + if (date == null) { + out.nullValue(); + } else { + out.value(date.getTime()); // Write as timestamp + } + } + + @Override + public Date read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + long timestamp = in.nextLong(); + return new Date(timestamp); + } +} +``` + +### Hierarchical Type Adapters + +Handle inheritance hierarchies: + +```java +Gson gson = new GsonBuilder() + .registerTypeHierarchyAdapter(Animal.class, new AnimalAdapter()) + .create(); + +// This adapter will be used for Animal and all its subclasses +public class AnimalAdapter implements JsonSerializer, JsonDeserializer { + @Override + public JsonElement serialize(Animal src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject result = new JsonObject(); + result.add("type", new JsonPrimitive(src.getClass().getSimpleName())); + result.add("properties", context.serialize(src, src.getClass())); + return result; + } + + @Override + public Animal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + JsonObject jsonObject = json.getAsJsonObject(); + String type = jsonObject.get("type").getAsString(); + JsonElement element = jsonObject.get("properties"); + + try { + Class clazz = Class.forName("com.example." + type); + return context.deserialize(element, clazz); + } catch (ClassNotFoundException e) { + throw new JsonParseException("Unknown element type: " + type, e); + } + } +} +``` + +## Null Handling + +Type adapters can handle nulls explicitly or use the `nullSafe()` wrapper: + +```java +public class NullSafeStringAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, String value) throws IOException { + out.value(value == null ? "NULL" : value); + } + + @Override + public String read(JsonReader in) throws IOException { + String value = in.nextString(); + return "NULL".equals(value) ? null : value; + } +} + +// Or use nullSafe wrapper +TypeAdapter adapter = new StringAdapter().nullSafe(); +``` + +## Accessing Delegate Adapters + +Get the next adapter in the chain to avoid infinite recursion: + +```java +Gson gson = new GsonBuilder() + .registerTypeAdapterFactory(new LoggingAdapterFactory()) + .create(); + +public class LoggingAdapterFactory implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + TypeAdapter delegate = gson.getDelegateAdapter(this, type); + + return new TypeAdapter() { + @Override + public void write(JsonWriter out, T value) throws IOException { + System.out.println("Serializing: " + value); + delegate.write(out, value); + } + + @Override + public T read(JsonReader in) throws IOException { + T result = delegate.read(in); + System.out.println("Deserialized: " + result); + return result; + } + }; + } +} +``` + +## Legacy Serializer/Deserializer Interfaces + +For simpler cases, you can use the legacy interfaces: + +```java { .api } +public interface JsonSerializer { + public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); +} + +public interface JsonDeserializer { + public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException; +} +``` + +**Context interfaces:** +```java { .api } +public interface JsonSerializationContext { + public JsonElement serialize(Object src); + public JsonElement serialize(Object src, Type typeOfSrc); +} + +public interface JsonDeserializationContext { + public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException; +} +``` + +**Usage:** +```java +public class PersonSerializer implements JsonSerializer { + @Override + public JsonElement serialize(Person src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject obj = new JsonObject(); + obj.addProperty("fullName", src.getFirstName() + " " + src.getLastName()); + obj.addProperty("age", src.getAge()); + return obj; + } +} + +Gson gson = new GsonBuilder() + .registerTypeAdapter(Person.class, new PersonSerializer()) + .create(); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-com-google-code-gson--gson/tile.json b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/tile.json new file mode 100644 index 000000000..c26ac4a5c --- /dev/null +++ b/.tessl/tiles/tessl/maven-com-google-code-gson--gson/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/maven-com-google-code-gson--gson", + "version": "2.13.0", + "docs": "docs/index.md", + "describes": "pkg:maven/com.google.code.gson/gson@2.13.1", + "summary": "Java library for converting Java objects to JSON and vice-versa." +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/docs/index.md b/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/docs/index.md new file mode 100644 index 000000000..865d44351 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/docs/index.md @@ -0,0 +1,200 @@ +# JaCoCo Agent + +JaCoCo Agent provides programmatic access to the JaCoCo runtime agent JAR file for Java code coverage analysis. This module serves as a wrapper and resource provider for the jacocoagent.jar file, offering APIs to extract, access, and deploy the coverage agent in various Java environments. + +## Package Information + +- **Package Name**: org.jacoco.agent +- **Package Type**: maven +- **Language**: Java +- **Installation**: + ```xml + + org.jacoco + org.jacoco.agent + 0.8.13 + + ``` + +## Core Imports + +```java +import org.jacoco.agent.AgentJar; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.net.URL; +``` + +## Basic Usage + +```java +import org.jacoco.agent.AgentJar; +import java.io.File; +import java.io.IOException; + +// Get the agent JAR as a URL +URL agentUrl = AgentJar.getResource(); + +// Get the agent JAR as an InputStream +InputStream agentStream = AgentJar.getResourceAsStream(); + +// Extract agent to a temporary location +File tempAgent = AgentJar.extractToTempLocation(); + +// Extract agent to a specific location +File specificLocation = new File("/path/to/jacocoagent.jar"); +AgentJar.extractTo(specificLocation); +``` + +## Capabilities + +### Agent Resource Access + +Access the embedded JaCoCo agent JAR file as a resource. + +```java { .api } +/** + * Returns a URL pointing to the JAR file. + * @return URL of the JAR file + */ +public static URL getResource(); + +/** + * Returns the content of the JAR file as a stream. + * @return content of the JAR file + */ +public static InputStream getResourceAsStream(); +``` + +**Usage Examples:** + +```java +// Access via URL +URL agentUrl = AgentJar.getResource(); +InputStream stream = agentUrl.openStream(); + +// Direct stream access with proper resource management +try (InputStream agentStream = AgentJar.getResourceAsStream()) { + // Use the stream for processing + // Stream is automatically closed when try block exits +} +``` + +### Agent Extraction + +Extract the embedded agent JAR to file system locations. + +```java { .api } +/** + * Extract the JaCoCo agent JAR and put it into a temporary location. This + * file should be deleted on exit, but may not if the VM is terminated + * @return Location of the Agent Jar file in the local file system. The file + * should exist and be readable. + * @throws IOException Unable to unpack agent jar + */ +public static File extractToTempLocation() throws IOException; + +/** + * Extract the JaCoCo agent JAR and put it into the specified location. + * @param destination Location to write JaCoCo Agent Jar to. Must be writeable + * @throws IOException Unable to unpack agent jar + */ +public static void extractTo(File destination) throws IOException; +``` + +**Usage Examples:** + +```java +// Extract to temporary location (automatically deleted on JVM exit) +File tempAgentFile = AgentJar.extractToTempLocation(); +System.out.println("Agent extracted to: " + tempAgentFile.getAbsolutePath()); + +// Extract to specific location +File agentFile = new File("./jacocoagent.jar"); +try { + AgentJar.extractTo(agentFile); + System.out.println("Agent extracted to: " + agentFile.getAbsolutePath()); +} catch (IOException e) { + System.err.println("Failed to extract agent: " + e.getMessage()); +} +``` + +## Types + +```java { .api } +public final class AgentJar { + // Private constructor - cannot be instantiated + private AgentJar(); + + // All methods are static +} +``` + +## Error Handling + +The JaCoCo Agent API uses two main types of exceptions: + +- **AssertionError**: Thrown when the embedded `/jacocoagent.jar` resource is not found. This typically indicates a build or packaging issue. The error includes a reference to `/org.jacoco.agent/README.TXT` for troubleshooting details. +- **IOException**: Thrown by extraction methods for I/O related failures, such as: + - Destination file is not writable + - Destination path does not exist + - Insufficient disk space + - File system permissions issues + +**Error Handling Example:** + +```java +try { + // Resource access - may throw AssertionError + URL agentUrl = AgentJar.getResource(); + + // File extraction - may throw IOException + File agentFile = new File("./jacocoagent.jar"); + AgentJar.extractTo(agentFile); + +} catch (AssertionError e) { + System.err.println("Agent resource not found. Check build configuration."); +} catch (IOException e) { + System.err.println("Failed to extract agent: " + e.getMessage()); +} +``` + +## Key Characteristics + +- **Utility Class**: AgentJar is a final class with only static methods and private constructor (cannot be instantiated) +- **Resource Provider**: Acts as a wrapper around the embedded `/jacocoagent.jar` resource within the JAR file +- **Thread Safety**: All methods are static and thread-safe +- **Self-Contained**: Includes the complete agent JAR as an embedded resource at runtime +- **Build Integration**: The agent JAR is created and embedded during the Maven build process +- **No External Dependencies**: Pure Java implementation using only standard library classes +- **Safe Resource Handling**: Internal implementation uses safe stream closing to prevent resource leaks + +## Integration Patterns + +Common usage patterns for integrating JaCoCo Agent in applications: + +**Testing Framework Integration:** +```java +// Extract agent for use with JVM arguments +File agent = AgentJar.extractToTempLocation(); +String javaagentArg = "-javaagent:" + agent.getAbsolutePath(); +// Use javaagentArg when launching test JVMs +``` + +**Build Tool Integration:** +```java +// Extract to build directory for distribution +File buildDir = new File("target/jacoco"); +buildDir.mkdirs(); +File agentJar = new File(buildDir, "jacocoagent.jar"); +AgentJar.extractTo(agentJar); +``` + +**Runtime Deployment:** +```java +// Use the built-in extraction method for deployment +File deploymentFile = new File("/path/to/deployment/jacocoagent.jar"); +AgentJar.extractTo(deploymentFile); +// The extractTo method handles stream management and proper copying +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/tile.json b/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/tile.json new file mode 100644 index 000000000..c7d81081e --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-jacoco--org-jacoco-agent/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/maven-org-jacoco--org-jacoco-agent", + "version": "0.8.0", + "docs": "docs/index.md", + "describes": "pkg:maven/org.jacoco/org.jacoco.agent@0.8.13", + "summary": "JaCoCo Agent provides programmatic access to the JaCoCo runtime agent JAR file for Java code coverage analysis." +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/assertions.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/assertions.md new file mode 100644 index 000000000..b449315b1 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/assertions.md @@ -0,0 +1,535 @@ +# Assertions and Assumptions + +Comprehensive assertion methods for verifying test conditions and assumptions for conditional test execution. JUnit Jupiter provides a rich set of assertion methods with clear failure messages and support for custom error messages. + +## Imports + +```java +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; +``` + +## Capabilities + +### Basic Assertions + +Core assertion methods for common verification scenarios. + +```java { .api } +/** + * Assert that two objects are equal + */ +static void assertEquals(Object expected, Object actual); +static void assertEquals(Object expected, Object actual, String message); +static void assertEquals(Object expected, Object actual, Supplier messageSupplier); + +/** + * Assert that two objects are not equal + */ +static void assertNotEquals(Object unexpected, Object actual); +static void assertNotEquals(Object unexpected, Object actual, String message); +static void assertNotEquals(Object unexpected, Object actual, Supplier messageSupplier); + +/** + * Assert that a condition is true + */ +static void assertTrue(boolean condition); +static void assertTrue(boolean condition, String message); +static void assertTrue(boolean condition, Supplier messageSupplier); + +/** + * Assert that a condition is false + */ +static void assertFalse(boolean condition); +static void assertFalse(boolean condition, String message); +static void assertFalse(boolean condition, Supplier messageSupplier); + +/** + * Assert that an object is null + */ +static void assertNull(Object actual); +static void assertNull(Object actual, String message); +static void assertNull(Object actual, Supplier messageSupplier); + +/** + * Assert that an object is not null + */ +static void assertNotNull(Object actual); +static void assertNotNull(Object actual, String message); +static void assertNotNull(Object actual, Supplier messageSupplier); +``` + +**Usage Examples:** + +```java +@Test +void testBasicAssertions() { + assertEquals(4, 2 + 2, "Simple addition should work"); + assertNotEquals(3, 2 + 2); + assertTrue(5 > 3, "5 should be greater than 3"); + assertFalse(5 < 3); + + String nullString = null; + String nonNullString = "hello"; + assertNull(nullString); + assertNotNull(nonNullString, "String should not be null"); +} +``` + +### Reference Assertions + +Assert object identity and reference equality. + +```java { .api } +/** + * Assert that two objects refer to the same object + */ +static void assertSame(Object expected, Object actual); +static void assertSame(Object expected, Object actual, String message); +static void assertSame(Object expected, Object actual, Supplier messageSupplier); + +/** + * Assert that two objects do not refer to the same object + */ +static void assertNotSame(Object unexpected, Object actual); +static void assertNotSame(Object unexpected, Object actual, String message); +static void assertNotSame(Object unexpected, Object actual, Supplier messageSupplier); +``` + +**Usage Example:** + +```java +@Test +void testReferenceAssertions() { + String str1 = new String("hello"); + String str2 = new String("hello"); + String str3 = str1; + + assertEquals(str1, str2); // Content equality + assertNotSame(str1, str2, "Different objects should not be same"); + assertSame(str1, str3, "Same reference should be same"); +} +``` + +### Array and Collection Assertions + +Specialized assertions for arrays and collections. + +```java { .api } +/** + * Assert that two arrays are equal + */ +static void assertArrayEquals(boolean[] expected, boolean[] actual); +static void assertArrayEquals(byte[] expected, byte[] actual); +static void assertArrayEquals(char[] expected, char[] actual); +static void assertArrayEquals(double[] expected, double[] actual); +static void assertArrayEquals(double[] expected, double[] actual, double delta); +static void assertArrayEquals(float[] expected, float[] actual); +static void assertArrayEquals(float[] expected, float[] actual, double delta); +static void assertArrayEquals(int[] expected, int[] actual); +static void assertArrayEquals(long[] expected, long[] actual); +static void assertArrayEquals(Object[] expected, Object[] actual); +static void assertArrayEquals(short[] expected, short[] actual); + +/** + * Assert that two iterables are equal + */ +static void assertIterableEquals(Iterable expected, Iterable actual); +static void assertIterableEquals(Iterable expected, Iterable actual, String message); +static void assertIterableEquals(Iterable expected, Iterable actual, Supplier messageSupplier); + +/** + * Assert that lines match with pattern support + */ +static void assertLinesMatch(List expectedLines, List actualLines); +static void assertLinesMatch(List expectedLines, List actualLines, String message); +static void assertLinesMatch(List expectedLines, List actualLines, Supplier messageSupplier); +static void assertLinesMatch(Stream expectedLines, Stream actualLines); +static void assertLinesMatch(Stream expectedLines, Stream actualLines, String message); +static void assertLinesMatch(Stream expectedLines, Stream actualLines, Supplier messageSupplier); +``` + +**Usage Examples:** + +```java +@Test +void testArrayAssertions() { + int[] expected = {1, 2, 3}; + int[] actual = {1, 2, 3}; + assertArrayEquals(expected, actual); + + double[] expectedDoubles = {1.1, 2.2, 3.3}; + double[] actualDoubles = {1.1, 2.2, 3.3}; + assertArrayEquals(expectedDoubles, actualDoubles, 0.01); +} + +@Test +void testIterableAssertions() { + List expected = Arrays.asList("a", "b", "c"); + List actual = Arrays.asList("a", "b", "c"); + assertIterableEquals(expected, actual); +} + +@Test +void testLinesMatch() { + List expected = Arrays.asList("Hello.*", "\\d+", "End"); + List actual = Arrays.asList("Hello World", "123", "End"); + assertLinesMatch(expected, actual); +} +``` + +### Exception Assertions + +Assert that specific exceptions are thrown or not thrown. + +```java { .api } +/** + * Assert that executable throws expected exception type + */ +static T assertThrows(Class expectedType, Executable executable); +static T assertThrows(Class expectedType, Executable executable, String message); +static T assertThrows(Class expectedType, Executable executable, Supplier messageSupplier); + +/** + * Assert that executable throws exactly the expected exception type + */ +static T assertThrowsExactly(Class expectedType, Executable executable); +static T assertThrowsExactly(Class expectedType, Executable executable, String message); +static T assertThrowsExactly(Class expectedType, Executable executable, Supplier messageSupplier); + +/** + * Assert that executable does not throw any exception + */ +static void assertDoesNotThrow(Executable executable); +static void assertDoesNotThrow(Executable executable, String message); +static void assertDoesNotThrow(Executable executable, Supplier messageSupplier); +static T assertDoesNotThrow(ThrowingSupplier supplier); +static T assertDoesNotThrow(ThrowingSupplier supplier, String message); +static T assertDoesNotThrow(ThrowingSupplier supplier, Supplier messageSupplier); +``` + +**Usage Examples:** + +```java +@Test +void testExceptionAssertions() { + // Assert specific exception is thrown + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> { throw new IllegalArgumentException("Invalid argument"); }, + "Should throw IllegalArgumentException" + ); + assertEquals("Invalid argument", exception.getMessage()); + + // Assert exact exception type + RuntimeException exactException = assertThrowsExactly( + RuntimeException.class, + () -> { throw new RuntimeException("Runtime error"); } + ); + + // Assert no exception is thrown + assertDoesNotThrow(() -> { + String result = "safe operation"; + return result; + }); + + // Assert no exception and return value + String result = assertDoesNotThrow(() -> "safe operation"); + assertEquals("safe operation", result); +} +``` + +### Timeout Assertions + +Assert that operations complete within specified time limits. + +```java { .api } +/** + * Assert that executable completes within timeout + */ +static void assertTimeout(Duration timeout, Executable executable); +static void assertTimeout(Duration timeout, Executable executable, String message); +static void assertTimeout(Duration timeout, Executable executable, Supplier messageSupplier); +static T assertTimeout(Duration timeout, ThrowingSupplier supplier); +static T assertTimeout(Duration timeout, ThrowingSupplier supplier, String message); +static T assertTimeout(Duration timeout, ThrowingSupplier supplier, Supplier messageSupplier); + +/** + * Assert that executable completes within timeout, preemptively aborting if it takes too long + */ +static void assertTimeoutPreemptively(Duration timeout, Executable executable); +static void assertTimeoutPreemptively(Duration timeout, Executable executable, String message); +static void assertTimeoutPreemptively(Duration timeout, Executable executable, Supplier messageSupplier); +static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier supplier); +static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier supplier, String message); +static T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier supplier, Supplier messageSupplier); +``` + +**Usage Examples:** + +```java +@Test +void testTimeoutAssertions() { + // Assert operation completes within timeout + assertTimeout(Duration.ofSeconds(2), () -> { + Thread.sleep(1000); // 1 second delay + }); + + // Assert with return value + String result = assertTimeout(Duration.ofSeconds(1), () -> { + return "Quick operation"; + }); + assertEquals("Quick operation", result); + + // Preemptive timeout (interrupts if takes too long) + assertTimeoutPreemptively(Duration.ofMillis(500), () -> { + Thread.sleep(100); // Short delay + }); +} +``` + +### Instance Type Assertions + +Assert object types and inheritance relationships. + +```java { .api } +/** + * Assert that object is instance of expected type + */ +static void assertInstanceOf(Class expectedType, Object actualValue); +static void assertInstanceOf(Class expectedType, Object actualValue, String message); +static void assertInstanceOf(Class expectedType, Object actualValue, Supplier messageSupplier); +static T assertInstanceOf(Class expectedType, Object actualValue); +static T assertInstanceOf(Class expectedType, Object actualValue, String message); +static T assertInstanceOf(Class expectedType, Object actualValue, Supplier messageSupplier); +``` + +**Usage Example:** + +```java +@Test +void testInstanceAssertions() { + Object obj = "Hello World"; + + // Simple instance check + assertInstanceOf(String.class, obj); + + // With type casting + String str = assertInstanceOf(String.class, obj, "Object should be String"); + assertEquals(11, str.length()); + + // Check inheritance + Number num = 42; + assertInstanceOf(Integer.class, num); +} +``` + +### Grouped Assertions + +Execute multiple assertions together and report all failures. + +```java { .api } +/** + * Group multiple assertions and execute all, reporting all failures + */ +static void assertAll(Executable... executables); +static void assertAll(String heading, Executable... executables); +static void assertAll(Collection executables); +static void assertAll(String heading, Collection executables); +static void assertAll(Stream executables); +static void assertAll(String heading, Stream executables); +``` + +**Usage Example:** + +```java +@Test +void testGroupedAssertions() { + Person person = new Person("John", "Doe", 30); + + assertAll("Person properties", + () -> assertEquals("John", person.getFirstName()), + () -> assertEquals("Doe", person.getLastName()), + () -> assertTrue(person.getAge() > 0), + () -> assertNotNull(person.getFullName()) + ); + + // Using collections + List assertions = Arrays.asList( + () -> assertEquals(4, 2 + 2), + () -> assertTrue(5 > 3), + () -> assertNotNull("test") + ); + assertAll("Math assertions", assertions); +} +``` + +### Failure Methods + +Explicitly fail tests with custom messages. + +```java { .api } +/** + * Explicitly fail test + */ +static void fail(); +static void fail(String message); +static void fail(String message, Throwable cause); +static void fail(Throwable cause); +static void fail(Supplier messageSupplier); +static T fail(); +static T fail(String message); +static T fail(String message, Throwable cause); +static T fail(Throwable cause); +static T fail(Supplier messageSupplier); +``` + +**Usage Example:** + +```java +@Test +void testFailMethods() { + boolean condition = false; + + if (!condition) { + fail("Condition was not met"); + } + + // With supplier for expensive message creation + if (!condition) { + fail(() -> "Complex message: " + generateComplexMessage()); + } + + // In switch statement + switch (value) { + case 1: /* handle */ break; + case 2: /* handle */ break; + default: fail("Unexpected value: " + value); + } +} +``` + +### Assumptions + +Conditional test execution based on assumptions about the test environment. + +```java { .api } +/** + * Assume that a condition is true, abort test if false + */ +static void assumeTrue(boolean assumption); +static void assumeTrue(boolean assumption, String message); +static void assumeTrue(boolean assumption, Supplier messageSupplier); +static void assumeTrue(BooleanSupplier assumptionSupplier); +static void assumeTrue(BooleanSupplier assumptionSupplier, String message); +static void assumeTrue(BooleanSupplier assumptionSupplier, Supplier messageSupplier); + +/** + * Assume that a condition is false, abort test if true + */ +static void assumeFalse(boolean assumption); +static void assumeFalse(boolean assumption, String message); +static void assumeFalse(boolean assumption, Supplier messageSupplier); +static void assumeFalse(BooleanSupplier assumptionSupplier); +static void assumeFalse(BooleanSupplier assumptionSupplier, String message); +static void assumeFalse(BooleanSupplier assumptionSupplier, Supplier messageSupplier); + +/** + * Execute test code only if assumption is true + */ +static void assumingThat(boolean assumption, Executable executable); +static void assumingThat(BooleanSupplier assumptionSupplier, Executable executable); +``` + +**Usage Examples:** + +```java +@Test +void testOnlyOnLinux() { + assumeTrue(System.getProperty("os.name").toLowerCase().contains("linux")); + + // This test will only run on Linux + // Will be skipped (not failed) on other operating systems + assertEquals("/", File.separator); +} + +@Test +void testWithPartialAssumption() { + // This part always runs + assertEquals(4, 2 + 2); + + // This part only runs if assumption is true + assumingThat(System.getProperty("env").equals("dev"), () -> { + // Development-only test code + assertEquals("localhost", getServerHost()); + }); + + // This part always runs + assertTrue(true); +} + +@Test +void testWithEnvironmentCheck() { + String env = System.getProperty("test.env"); + assumeFalse("prod".equals(env), "Not running destructive test in production"); + + // Destructive test that should not run in production + database.deleteAllData(); +} +``` + +### Assertion Failure Builder + +Build custom assertion failures with detailed information. + +```java { .api } +class AssertionFailureBuilder { + /** + * Create new assertion failure builder + */ + static AssertionFailureBuilder assertionFailure(); + + /** + * Set failure message + */ + AssertionFailureBuilder message(String message); + + /** + * Set expected value + */ + AssertionFailureBuilder expected(Object expected); + + /** + * Set actual value + */ + AssertionFailureBuilder actual(Object actual); + + /** + * Set cause exception + */ + AssertionFailureBuilder cause(Throwable cause); + + /** + * Build the assertion failure + */ + AssertionFailedError build(); +} +``` + +**Usage Example:** + +```java +@Test +void testCustomAssertion() { + String expected = "hello"; + String actual = "world"; + + if (!expected.equals(actual)) { + throw AssertionFailureBuilder.assertionFailure() + .message("Strings should match") + .expected(expected) + .actual(actual) + .build(); + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/conditional-execution.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/conditional-execution.md new file mode 100644 index 000000000..621c785cf --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/conditional-execution.md @@ -0,0 +1,438 @@ +# Conditional Execution + +Rich set of built-in conditions for controlling test execution based on runtime environment, system properties, and custom logic. Tests can be enabled or disabled dynamically based on various criteria. + +## Imports + +```java +import org.junit.jupiter.api.condition.*; +import static org.junit.jupiter.api.Assertions.*; +``` + +## Capabilities + +### Operating System Conditions + +Enable or disable tests based on the operating system. + +```java { .api } +/** + * Enable test on specific operating systems + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledOnOsCondition.class) +@interface EnabledOnOs { + OS[] value(); + String disabledReason() default ""; +} + +/** + * Disable test on specific operating systems + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledOnOsCondition.class) +@interface DisabledOnOs { + OS[] value(); + String disabledReason() default ""; +} + +/** + * Operating system enumeration + */ +enum OS { + LINUX, + MAC, + WINDOWS, + AIX, + SOLARIS, + OTHER +} +``` + +**Usage Examples:** + +```java +class OsSpecificTest { + + @Test + @EnabledOnOs(OS.LINUX) + void testOnLinuxOnly() { + assertEquals("/", File.separator); + } + + @Test + @EnabledOnOs({OS.WINDOWS, OS.MAC}) + void testOnWindowsOrMac() { + assertNotEquals("/", File.separator); + } + + @Test + @DisabledOnOs(value = OS.WINDOWS, disabledReason = "Windows path handling differs") + void testUnixPaths() { + assertTrue(Paths.get("/usr/local").isAbsolute()); + } +} +``` + +### Java Runtime Environment Conditions + +Control execution based on JRE version. + +```java { .api } +/** + * Enable test on specific JRE versions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledOnJreCondition.class) +@interface EnabledOnJre { + JRE[] value(); + String disabledReason() default ""; +} + +/** + * Disable test on specific JRE versions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledOnJreCondition.class) +@interface DisabledOnJre { + JRE[] value(); + String disabledReason() default ""; +} + +/** + * Enable test for JRE version ranges + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledForJreRangeCondition.class) +@interface EnabledForJreRange { + JRE min() default JRE.JAVA_8; + JRE max() default JRE.OTHER; + String disabledReason() default ""; +} + +/** + * Disable test for JRE version ranges + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledForJreRangeCondition.class) +@interface DisabledForJreRange { + JRE min() default JRE.JAVA_8; + JRE max() default JRE.OTHER; + String disabledReason() default ""; +} +``` + +**Usage Examples:** + +```java +class JreSpecificTest { + + @Test + @EnabledOnJre(JRE.JAVA_8) + void testOnJava8Only() { + // Java 8 specific functionality + } + + @Test + @EnabledForJreRange(min = JRE.JAVA_11, max = JRE.JAVA_17) + void testOnJava11To17() { + // Features available in Java 11-17 + } + + @Test + @DisabledOnJre(value = JRE.JAVA_8, disabledReason = "Lambda syntax not supported") + void testWithModernJavaFeatures() { + // Modern Java features + var list = List.of("item1", "item2"); + assertFalse(list.isEmpty()); + } +} +``` + +### System Property Conditions + +Execute tests conditionally based on system properties. + +```java { .api } +/** + * Enable test if system property matches + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(EnabledIfSystemProperties.class) +@ExtendWith(EnabledIfSystemPropertyCondition.class) +@interface EnabledIfSystemProperty { + String named(); + String matches(); + String disabledReason() default ""; +} + +/** + * Container for multiple system property conditions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledIfSystemPropertyCondition.class) +@interface EnabledIfSystemProperties { + EnabledIfSystemProperty[] value(); +} + +/** + * Disable test if system property matches + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(DisabledIfSystemProperties.class) +@ExtendWith(DisabledIfSystemPropertyCondition.class) +@interface DisabledIfSystemProperty { + String named(); + String matches(); + String disabledReason() default ""; +} + +/** + * Container for multiple system property conditions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledIfSystemPropertyCondition.class) +@interface DisabledIfSystemProperties { + DisabledIfSystemProperty[] value(); +} +``` + +**Usage Examples:** + +```java +class SystemPropertyTest { + + @Test + @EnabledIfSystemProperty(named = "env", matches = "dev") + void testInDevelopmentOnly() { + // Development environment specific test + } + + @Test + @EnabledIfSystemProperty(named = "debug", matches = "true") + void testWithDebugEnabled() { + // Debug mode specific test + } + + @Test + @DisabledIfSystemProperty(named = "ci", matches = "true", + disabledReason = "Flaky in CI environment") + void testDisabledInCI() { + // Test that's unreliable in CI + } + + @Test + @EnabledIfSystemProperties({ + @EnabledIfSystemProperty(named = "env", matches = "test"), + @EnabledIfSystemProperty(named = "db.enabled", matches = "true") + }) + void testWithMultipleProperties() { + // Test requiring multiple system properties + } +} +``` + +### Environment Variable Conditions + +Execute tests conditionally based on environment variables. + +```java { .api } +/** + * Enable test if environment variable matches + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(EnabledIfEnvironmentVariables.class) +@ExtendWith(EnabledIfEnvironmentVariableCondition.class) +@interface EnabledIfEnvironmentVariable { + String named(); + String matches(); + String disabledReason() default ""; +} + +/** + * Container for multiple environment variable conditions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledIfEnvironmentVariableCondition.class) +@interface EnabledIfEnvironmentVariables { + EnabledIfEnvironmentVariable[] value(); +} + +/** + * Disable test if environment variable matches + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(DisabledIfEnvironmentVariables.class) +@ExtendWith(DisabledIfEnvironmentVariableCondition.class) +@interface DisabledIfEnvironmentVariable { + String named(); + String matches(); + String disabledReason() default ""; +} + +/** + * Container for multiple environment variable conditions + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledIfEnvironmentVariableCondition.class) +@interface DisabledIfEnvironmentVariables { + DisabledIfEnvironmentVariable[] value(); +} +``` + +**Usage Examples:** + +```java +class EnvironmentVariableTest { + + @Test + @EnabledIfEnvironmentVariable(named = "ENV", matches = "production") + void testInProductionOnly() { + // Production-specific test + } + + @Test + @EnabledIfEnvironmentVariable(named = "DATABASE_URL", matches = ".*localhost.*") + void testWithLocalDatabase() { + // Test requiring local database + } + + @Test + @DisabledIfEnvironmentVariable(named = "SKIP_SLOW_TESTS", matches = "true") + void slowTest() throws InterruptedException { + Thread.sleep(5000); + assertTrue(true); + } +} +``` + +### Custom Condition Methods + +Execute tests based on custom boolean methods. + +```java { .api } +/** + * Enable test if custom condition method returns true + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(EnabledIfCondition.class) +@interface EnabledIf { + /** + * Method name that returns boolean + */ + String value(); + String disabledReason() default ""; +} + +/** + * Disable test if custom condition method returns true + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(DisabledIfCondition.class) +@interface DisabledIf { + /** + * Method name that returns boolean + */ + String value(); + String disabledReason() default ""; +} +``` + +**Usage Examples:** + +```java +class CustomConditionTest { + + @Test + @EnabledIf("isExternalServiceAvailable") + void testWithExternalService() { + // Test that requires external service + } + + @Test + @DisabledIf("isWeekend") + void testDisabledOnWeekends() { + // Test that shouldn't run on weekends + } + + static boolean isExternalServiceAvailable() { + try { + // Check if external service is reachable + URL url = new URL("http://api.example.com/health"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(1000); + return connection.getResponseCode() == 200; + } catch (Exception e) { + return false; + } + } + + static boolean isWeekend() { + DayOfWeek today = LocalDate.now().getDayOfWeek(); + return today == DayOfWeek.SATURDAY || today == DayOfWeek.SUNDAY; + } +} +``` + +### GraalVM Native Image Conditions + +Control execution in GraalVM native image contexts. + +```java { .api } +/** + * Enable test only in GraalVM native image + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface EnabledInNativeImage { + String disabledReason() default ""; +} + +/** + * Disable test in GraalVM native image + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface DisabledInNativeImage { + String disabledReason() default ""; +} +``` + +**Usage Examples:** + +```java +class NativeImageTest { + + @Test + @EnabledInNativeImage + void testNativeImageSpecificBehavior() { + // Test behavior specific to native image + } + + @Test + @DisabledInNativeImage(disabledReason = "Reflection not available in native image") + void testWithReflection() { + // Test using reflection APIs + Class clazz = String.class; + Method[] methods = clazz.getDeclaredMethods(); + assertTrue(methods.length > 0); + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/core-testing.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/core-testing.md new file mode 100644 index 000000000..b8a152513 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/core-testing.md @@ -0,0 +1,571 @@ +# Core Testing API + +Essential testing annotations and lifecycle methods that form the foundation of JUnit Jupiter tests. These provide the basic structure for organizing and executing tests with modern Java features. + +## Imports + +```java +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; +``` + +## Capabilities + +### Test Annotation + +Marks a method as a test method that should be executed by the test engine. + +```java { .api } +/** + * Marks a method as a test method + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Test { +} +``` + +**Usage Example:** + +```java +class MyTest { + @Test + void shouldCalculateCorrectly() { + // Test implementation + assertEquals(4, 2 + 2); + } +} +``` + +### Lifecycle Annotations + +Control test execution lifecycle with setup and teardown methods. + +```java { .api } +/** + * Executed once before all test methods in the class + * Method must be static + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface BeforeAll { +} + +/** + * Executed before each individual test method + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface BeforeEach { +} + +/** + * Executed after each individual test method + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface AfterEach { +} + +/** + * Executed once after all test methods in the class + * Method must be static + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface AfterAll { +} +``` + +**Usage Example:** + +```java +class DatabaseTest { + static Database database; + Connection connection; + + @BeforeAll + static void initDatabase() { + database = new Database(); + database.start(); + } + + @AfterAll + static void cleanupDatabase() { + database.stop(); + } + + @BeforeEach + void openConnection() { + connection = database.openConnection(); + } + + @AfterEach + void closeConnection() { + if (connection != null) { + connection.close(); + } + } + + @Test + void testQuery() { + // Test with connection + } +} +``` + +### Display Names + +Customize test names for better readability in test reports. + +```java { .api } +/** + * Custom display name for tests and test classes + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface DisplayName { + String value(); +} + +/** + * Generate display names using a specific strategy + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@interface DisplayNameGeneration { + Class value(); +} +``` + +**Usage Example:** + +```java +@DisplayName("Calculator Tests") +class CalculatorTest { + + @Test + @DisplayName("Addition should work for positive numbers") + void testAddition() { + assertEquals(5, 2 + 3); + } + + @Test + @DisplayName("Division by zero should throw exception") + void testDivisionByZero() { + assertThrows(ArithmeticException.class, () -> 10 / 0); + } +} +``` + +### Display Name Generators + +Built-in strategies for generating display names automatically. + +```java { .api } +interface DisplayNameGenerator { + String generateDisplayNameForClass(Class testClass); + String generateDisplayNameForNestedClass(Class nestedClass); + String generateDisplayNameForMethod(Class testClass, Method testMethod); + + class Standard implements DisplayNameGenerator { } + class Simple implements DisplayNameGenerator { } + class ReplaceUnderscores implements DisplayNameGenerator { } + class IndicativeSentences implements DisplayNameGenerator { } +} +``` + +### Nested Tests + +Organize related tests in hierarchical structure using nested classes. + +```java { .api } +/** + * Marks a nested class as a test class + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@interface Nested { +} +``` + +**Usage Example:** + +```java +class AccountTest { + + @Test + void testCreateAccount() { + // Test account creation + } + + @Nested + @DisplayName("When account has balance") + class WhenAccountHasBalance { + + Account account; + + @BeforeEach + void createAccountWithBalance() { + account = new Account(100); + } + + @Test + @DisplayName("withdraw should decrease balance") + void withdrawShouldDecreaseBalance() { + account.withdraw(20); + assertEquals(80, account.getBalance()); + } + + @Nested + @DisplayName("And withdrawal amount exceeds balance") + class AndWithdrawalExceedsBalance { + + @Test + @DisplayName("should throw InsufficientFundsException") + void shouldThrowException() { + assertThrows(InsufficientFundsException.class, + () -> account.withdraw(150)); + } + } + } +} +``` + +### Test Disabling + +Disable tests temporarily or conditionally. + +```java { .api } +/** + * Disable test execution with optional reason + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Disabled { + String value() default ""; +} +``` + +**Usage Example:** + +```java +class FeatureTest { + + @Test + @Disabled("Feature not yet implemented") + void testNewFeature() { + // This test won't run + } + + @Test + @Disabled + void temporarilyDisabled() { + // This test won't run either + } +} +``` + +### Test Tagging + +Tag tests for filtering and selective execution. + +```java { .api } +/** + * Tag a test for filtering + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(Tags.class) +@interface Tag { + String value(); +} + +/** + * Container for multiple tags + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Tags { + Tag[] value(); +} +``` + +**Usage Example:** + +```java +class IntegrationTest { + + @Test + @Tag("fast") + void testQuickOperation() { + // Fast test + } + + @Test + @Tag("slow") + @Tag("integration") + void testDatabaseIntegration() { + // Slow integration test + } + + @Test + @Tags({@Tag("smoke"), @Tag("critical")}) + void testCriticalPath() { + // Critical smoke test + } +} +``` + +### Repeated Tests + +Execute the same test multiple times with repetition information. + +```java { .api } +/** + * Repeat test execution multiple times + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@interface RepeatedTest { + int value(); + String name() default ""; +} +``` + +**Usage Example:** + +```java +class RandomTest { + + @RepeatedTest(10) + void testRandomBehavior() { + int random = (int) (Math.random() * 100); + assertTrue(random >= 0 && random < 100); + } + + @RepeatedTest(value = 5, name = "Run {currentRepetition} of {totalRepetitions}") + void testWithCustomName(RepetitionInfo repetitionInfo) { + System.out.println("Repetition: " + repetitionInfo.getCurrentRepetition()); + } +} +``` + +### Test Information + +Access test metadata at runtime. + +```java { .api } +interface TestInfo { + String getDisplayName(); + Set getTags(); + Optional> getTestClass(); + Optional getTestMethod(); +} + +interface RepetitionInfo { + int getCurrentRepetition(); + int getTotalRepetitions(); +} +``` + +**Usage Example:** + +```java +class InfoTest { + + @Test + void testWithInfo(TestInfo testInfo) { + System.out.println("Test name: " + testInfo.getDisplayName()); + System.out.println("Tags: " + testInfo.getTags()); + } + + @RepeatedTest(3) + void repeatedTestWithInfo(RepetitionInfo repetitionInfo) { + System.out.println("Repetition " + repetitionInfo.getCurrentRepetition() + + " of " + repetitionInfo.getTotalRepetitions()); + } +} +``` + +### Test Ordering + +Control the order of test execution. + +```java { .api } +/** + * Configure test method execution order + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@interface TestMethodOrder { + Class value(); +} + +/** + * Configure test class execution order + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@interface TestClassOrder { + Class value(); +} + +/** + * Specify execution order + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Order { + int value(); +} +``` + +**Usage Example:** + +```java +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +class OrderedTest { + + @Test + @Order(3) + void testThird() { + // Runs third + } + + @Test + @Order(1) + void testFirst() { + // Runs first + } + + @Test + @Order(2) + void testSecond() { + // Runs second + } +} +``` + +### Test Instance Lifecycle + +Control how test instances are created and managed. + +```java { .api } +/** + * Configure test instance lifecycle + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@interface TestInstance { + Lifecycle value(); + + enum Lifecycle { + PER_METHOD, // Default: new instance per test method + PER_CLASS // One instance per test class + } +} +``` + +**Usage Example:** + +```java +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class SharedStateTest { + int counter = 0; + + @Test + void firstTest() { + counter++; + assertEquals(1, counter); + } + + @Test + void secondTest() { + counter++; + assertEquals(2, counter); // Works because same instance + } +} +``` + +### Test Timeouts + +Configure execution timeouts for individual tests or entire test classes. + +```java { .api } +/** + * Configure test execution timeout + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Timeout { + /** + * Timeout value + */ + long value(); + + /** + * Time unit for timeout value + */ + TimeUnit unit() default TimeUnit.SECONDS; + + /** + * Thread mode for timeout enforcement + */ + ThreadMode threadMode() default ThreadMode.SAME_THREAD; + + enum ThreadMode { + /** + * Execute in same thread with timeout monitoring + */ + SAME_THREAD, + + /** + * Execute in separate thread and interrupt on timeout + */ + SEPARATE_THREAD + } +} +``` + +**Usage Examples:** + +```java +class TimeoutTest { + + @Test + @Timeout(5) // 5 seconds + void testWithTimeout() throws InterruptedException { + Thread.sleep(1000); // Will pass + } + + @Test + @Timeout(value = 500, unit = TimeUnit.MILLISECONDS) + void testWithMillisecondTimeout() { + // Test must complete within 500ms + performQuickOperation(); + } + + @Test + @Timeout(value = 10, threadMode = Timeout.ThreadMode.SEPARATE_THREAD) + void testWithSeparateThread() throws InterruptedException { + // Will be interrupted after 10 seconds if still running + Thread.sleep(5000); + } +} + +@Timeout(30) // Default 30 second timeout for all tests in class +class SlowTestsWithTimeout { + + @Test + void slowTest1() throws InterruptedException { + Thread.sleep(10000); // 10 seconds - within class timeout + } + + @Test + @Timeout(60) // Override class timeout for this test + void verySlowTest() throws InterruptedException { + Thread.sleep(45000); // 45 seconds - within method timeout + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/dynamic-tests.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/dynamic-tests.md new file mode 100644 index 000000000..9fea71247 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/dynamic-tests.md @@ -0,0 +1,395 @@ +# Dynamic Tests + +Runtime test generation capabilities that allow creating tests programmatically during execution. Dynamic tests enable flexible test scenarios based on runtime data and conditions. + +## Imports + +```java +import org.junit.jupiter.api.*; +import java.util.stream.Stream; +import java.util.Collection; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.DynamicTest.dynamicTest; +import static org.junit.jupiter.api.DynamicContainer.dynamicContainer; +``` + +## Capabilities + +### Test Factory Annotation + +Mark methods that generate dynamic tests at runtime. + +```java { .api } +/** + * Marks a method as a factory for dynamic tests + * Method must return Stream, Collection, Iterable, or Iterator of DynamicNode + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@interface TestFactory { +} +``` + +### Dynamic Test Creation + +Create individual dynamic test instances. + +```java { .api } +/** + * A dynamically generated test + */ +class DynamicTest extends DynamicNode { + /** + * Create a dynamic test with display name and executable + */ + static DynamicTest dynamicTest(String displayName, Executable executable); + + /** + * Create a dynamic test with display name, URI, and executable + */ + static DynamicTest dynamicTest(String displayName, URI testSourceUri, Executable executable); + + /** + * Create a stream of dynamic tests from input data + */ + static Stream stream(Iterator inputGenerator, + Function displayNameGenerator, + ThrowingConsumer testExecutor); + + /** + * Create a stream of dynamic tests from input stream + */ + static Stream stream(Stream inputStream, + Function displayNameGenerator, + ThrowingConsumer testExecutor); +} +``` + +**Usage Examples:** + +```java +class DynamicTestExample { + + @TestFactory + Stream simpleTests() { + return Stream.of("apple", "banana", "cherry") + .map(fruit -> DynamicTest.dynamicTest( + "test " + fruit, + () -> { + assertNotNull(fruit); + assertTrue(fruit.length() > 3); + } + )); + } + + @TestFactory + Collection numbersTest() { + return Arrays.asList( + DynamicTest.dynamicTest("Test 1", () -> assertEquals(2, 1 + 1)), + DynamicTest.dynamicTest("Test 2", () -> assertEquals(4, 2 * 2)), + DynamicTest.dynamicTest("Test 3", () -> assertEquals(9, 3 * 3)) + ); + } + + @TestFactory + Stream dataStreamTests() { + List data = Arrays.asList("alpha", "beta", "gamma"); + + return DynamicTest.stream( + data.stream(), + name -> "Processing " + name, + value -> { + assertNotNull(value); + assertTrue(value.length() > 3); + assertFalse(value.isEmpty()); + } + ); + } +} +``` + +### Dynamic Container Creation + +Group related dynamic tests in containers. + +```java { .api } +/** + * A container for dynamic tests or other containers + */ +class DynamicContainer extends DynamicNode { + /** + * Create a dynamic container with display name and children + */ + static DynamicContainer dynamicContainer(String displayName, Stream children); + + /** + * Create a dynamic container with display name, URI, and children + */ + static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Stream children); + + /** + * Create a dynamic container with display name and iterable children + */ + static DynamicContainer dynamicContainer(String displayName, Iterable children); + + /** + * Create a dynamic container with display name, URI, and iterable children + */ + static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Iterable children); +} +``` + +**Usage Examples:** + +```java +class DynamicContainerExample { + + @TestFactory + Stream nestedTests() { + return Stream.of( + DynamicContainer.dynamicContainer("String Tests", Stream.of( + DynamicTest.dynamicTest("Test empty string", () -> assertTrue("".isEmpty())), + DynamicTest.dynamicTest("Test non-empty string", () -> assertFalse("hello".isEmpty())) + )), + + DynamicContainer.dynamicContainer("Number Tests", Stream.of( + DynamicTest.dynamicTest("Test positive", () -> assertTrue(5 > 0)), + DynamicTest.dynamicTest("Test negative", () -> assertTrue(-5 < 0)) + )) + ); + } + + @TestFactory + Stream hierarchicalTests() { + return Stream.of("Category A", "Category B") + .map(category -> DynamicContainer.dynamicContainer( + category, + IntStream.range(1, 4) + .mapToObj(i -> DynamicTest.dynamicTest( + category + " Test " + i, + () -> { + assertNotNull(category); + assertTrue(i > 0); + } + )) + )); + } +} +``` + +### Dynamic Node Base + +Base class for all dynamic test elements. + +```java { .api } +/** + * Base class for dynamic tests and containers + */ +abstract class DynamicNode { + /** + * Get display name + */ + String getDisplayName(); + + /** + * Get test source URI + */ + Optional getTestSourceUri(); +} +``` + +### Named Interface + +Interface for providing names to test components. + +```java { .api } +/** + * Interface for named test components + */ +interface Named { + /** + * Get the name + */ + String getName(); + + /** + * Create Named instance with given name and payload + */ + static Named of(String name, T payload); +} + +/** + * Named executable for dynamic test creation + */ +interface NamedExecutable extends Named { + /** + * Get the executable + */ + Executable getExecutable(); + + /** + * Create NamedExecutable with name and executable + */ + static NamedExecutable of(String name, Executable executable); +} +``` + +**Usage Examples:** + +```java +class NamedTestExample { + + @TestFactory + Stream namedTests() { + List> testData = Arrays.asList( + Named.of("First test", "alpha"), + Named.of("Second test", "beta"), + Named.of("Third test", "gamma") + ); + + return testData.stream() + .map(namedData -> DynamicTest.dynamicTest( + namedData.getName(), + () -> { + String value = namedData.getPayload(); + assertNotNull(value); + assertTrue(value.length() > 3); + } + )); + } + + @TestFactory + Stream namedExecutableTests() { + List executables = Arrays.asList( + NamedExecutable.of("Test addition", () -> assertEquals(4, 2 + 2)), + NamedExecutable.of("Test subtraction", () -> assertEquals(0, 2 - 2)), + NamedExecutable.of("Test multiplication", () -> assertEquals(4, 2 * 2)) + ); + + return executables.stream() + .map(namedExec -> DynamicTest.dynamicTest( + namedExec.getName(), + namedExec.getExecutable() + )); + } +} +``` + +### Complex Dynamic Test Scenarios + +Advanced patterns for dynamic test generation. + +**Database-driven Tests:** + +```java +class DatabaseDrivenTests { + + @TestFactory + Stream testAllUsers() { + UserRepository repository = new UserRepository(); + + return repository.findAll().stream() + .map(user -> DynamicTest.dynamicTest( + "Validate user: " + user.getUsername(), + () -> { + assertNotNull(user.getEmail()); + assertTrue(user.getAge() >= 0); + assertFalse(user.getUsername().isEmpty()); + } + )); + } + + @TestFactory + Stream testUsersByRole() { + UserRepository repository = new UserRepository(); + Map> usersByRole = repository.findAll().stream() + .collect(Collectors.groupingBy(User::getRole)); + + return usersByRole.entrySet().stream() + .map(entry -> DynamicContainer.dynamicContainer( + "Role: " + entry.getKey(), + entry.getValue().stream() + .map(user -> DynamicTest.dynamicTest( + "Test " + user.getUsername(), + () -> validateUserInRole(user, entry.getKey()) + )) + )); + } + + private void validateUserInRole(User user, String expectedRole) { + assertEquals(expectedRole, user.getRole()); + assertNotNull(user.getPermissions()); + assertFalse(user.getPermissions().isEmpty()); + } +} +``` + +**Configuration-based Tests:** + +```java +class ConfigurationBasedTests { + + @TestFactory + Stream testConfigurations() throws IOException { + Properties configs = loadTestConfigurations(); + + return configs.entrySet().stream() + .map(entry -> DynamicTest.dynamicTest( + "Test config: " + entry.getKey(), + () -> { + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + + assertNotNull(value, "Configuration value should not be null"); + validateConfigurationValue(key, value); + } + )); + } + + @TestFactory + Stream testConfigurationGroups() throws IOException { + Map configGroups = loadConfigurationGroups(); + + return configGroups.entrySet().stream() + .map(group -> DynamicContainer.dynamicContainer( + "Config Group: " + group.getKey(), + group.getValue().entrySet().stream() + .map(config -> DynamicTest.dynamicTest( + "Test " + config.getKey(), + () -> validateConfigurationValue( + (String) config.getKey(), + (String) config.getValue() + ) + )) + )); + } + + private Properties loadTestConfigurations() throws IOException { + Properties props = new Properties(); + props.load(getClass().getResourceAsStream("/test-config.properties")); + return props; + } + + private Map loadConfigurationGroups() { + // Load different configuration groups + return Map.of( + "database", loadDatabaseConfigs(), + "security", loadSecurityConfigs(), + "performance", loadPerformanceConfigs() + ); + } + + private void validateConfigurationValue(String key, String value) { + switch (key) { + case "timeout": + assertTrue(Integer.parseInt(value) > 0); + break; + case "url": + assertTrue(value.startsWith("http")); + break; + default: + assertNotNull(value); + } + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/extensions.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/extensions.md new file mode 100644 index 000000000..8b3cd2cb2 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/extensions.md @@ -0,0 +1,849 @@ +# Extensions and Lifecycle + +JUnit Jupiter's powerful extension model allows customizing test behavior, dependency injection, and integration with external frameworks. Extensions provide hooks into the test lifecycle and enable sophisticated test customizations. + +## Imports + +```java +import org.junit.jupiter.api.extension.*; +import static org.junit.jupiter.api.Assertions.*; +``` + +## Capabilities + +### Extension Registration + +Register extensions declaratively or programmatically. + +```java { .api } +/** + * Register extensions declaratively on test classes and methods + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(ExtendWith.List.class) +@interface ExtendWith { + /** + * Extension classes to register + */ + Class[] value(); + + @Target({ElementType.TYPE, ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + @interface List { + ExtendWith[] value(); + } +} + +/** + * Register extension instance via static field + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@interface RegisterExtension { +} + +/** + * Base extension interface - marker interface for all extensions + */ +interface Extension { +} +``` + +**Usage Examples:** + +```java +// Declarative registration +@ExtendWith(DatabaseExtension.class) +@ExtendWith(MockitoExtension.class) +class MyTest { + + @Test + void testWithExtensions() { + // Extensions are active + } +} + +// Programmatic registration +class MyTest { + + @RegisterExtension + static DatabaseExtension database = new DatabaseExtension("testdb"); + + @RegisterExtension + MockServerExtension mockServer = new MockServerExtension(8080); + + @Test + void testWithProgrammaticExtensions() { + // Extensions configured and active + } +} +``` + +### Lifecycle Callback Extensions + +Hook into test lifecycle events. + +```java { .api } +/** + * Callback before all tests in container + */ +interface BeforeAllCallback extends Extension { + void beforeAll(ExtensionContext context) throws Exception; +} + +/** + * Callback before each test method + */ +interface BeforeEachCallback extends Extension { + void beforeEach(ExtensionContext context) throws Exception; +} + +/** + * Callback before test method execution (after @BeforeEach) + */ +interface BeforeTestExecutionCallback extends Extension { + void beforeTestExecution(ExtensionContext context) throws Exception; +} + +/** + * Callback after test method execution (before @AfterEach) + */ +interface AfterTestExecutionCallback extends Extension { + void afterTestExecution(ExtensionContext context) throws Exception; +} + +/** + * Callback after each test method + */ +interface AfterEachCallback extends Extension { + void afterEach(ExtensionContext context) throws Exception; +} + +/** + * Callback after all tests in container + */ +interface AfterAllCallback extends Extension { + void afterAll(ExtensionContext context) throws Exception; +} +``` + +**Usage Example:** + +```java +class TimingExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback { + + private static final String START_TIME = "start time"; + + @Override + public void beforeTestExecution(ExtensionContext context) throws Exception { + getStore(context).put(START_TIME, System.currentTimeMillis()); + } + + @Override + public void afterTestExecution(ExtensionContext context) throws Exception { + Method testMethod = context.getRequiredTestMethod(); + long startTime = getStore(context).remove(START_TIME, long.class); + long duration = System.currentTimeMillis() - startTime; + + System.out.printf("Method [%s] took %s ms.%n", testMethod.getName(), duration); + } + + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore(ExtensionContext.Namespace.create(getClass(), context.getRequiredTestMethod())); + } +} + +@ExtendWith(TimingExtension.class) +class TimedTest { + + @Test + void testThatTakesTime() throws InterruptedException { + Thread.sleep(100); + assertTrue(true); + } +} +``` + +### Parameter Resolution Extensions + +Inject custom parameters into test methods and constructors. + +```java { .api } +/** + * Resolve parameters for test methods and constructors + */ +interface ParameterResolver extends Extension { + /** + * Check if this resolver supports the parameter + */ + boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException; + + /** + * Resolve the parameter value + */ + Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException; +} + +/** + * Parameter context information + */ +interface ParameterContext { + Parameter getParameter(); + int getIndex(); + Optional getTarget(); + boolean isAnnotated(Class annotationType); + Optional findAnnotation(Class annotationType); + List findRepeatableAnnotations(Class annotationType); +} + +/** + * Type-based parameter resolver base class + */ +abstract class TypeBasedParameterResolver implements ParameterResolver { + private final Class parameterType; + + protected TypeBasedParameterResolver(Class parameterType) { + this.parameterType = parameterType; + } + + @Override + public final boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return parameterType.equals(parameterContext.getParameter().getType()); + } + + @Override + public final Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return resolveParameter(extensionContext); + } + + /** + * Resolve parameter of the supported type + */ + public abstract T resolveParameter(ExtensionContext extensionContext); +} +``` + +**Usage Examples:** + +```java +class DatabaseConnectionResolver implements ParameterResolver { + + @Override + public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return parameterContext.getParameter().getType() == Connection.class; + } + + @Override + public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { + return createDatabaseConnection(); + } + + private Connection createDatabaseConnection() { + // Create and return database connection + return DriverManager.getConnection("jdbc:h2:mem:test"); + } +} + +class TempDirectoryResolver extends TypeBasedParameterResolver { + + public TempDirectoryResolver() { + super(Path.class); + } + + @Override + public Path resolveParameter(ExtensionContext extensionContext) { + return Files.createTempDirectory("junit-test"); + } +} + +@ExtendWith({DatabaseConnectionResolver.class, TempDirectoryResolver.class}) +class DatabaseTest { + + @Test + void testWithInjectedParameters(Connection connection, Path tempDir) { + assertNotNull(connection); + assertNotNull(tempDir); + assertTrue(Files.exists(tempDir)); + } +} +``` + +### Conditional Execution Extensions + +Control when tests should be executed. + +```java { .api } +/** + * Determine whether test should be executed + */ +interface ExecutionCondition extends Extension { + /** + * Evaluate execution condition + */ + ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context); +} + +/** + * Result of condition evaluation + */ +class ConditionEvaluationResult { + /** + * Create enabled result + */ + static ConditionEvaluationResult enabled(String reason); + + /** + * Create disabled result + */ + static ConditionEvaluationResult disabled(String reason); + + /** + * Check if execution is disabled + */ + boolean isDisabled(); + + /** + * Get reason for the result + */ + Optional getReason(); +} +``` + +**Usage Example:** + +```java +class SystemPropertyCondition implements ExecutionCondition { + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + Optional annotation = context.getElement() + .map(element -> element.getAnnotation(SystemProperty.class)); + + if (annotation.isPresent()) { + SystemProperty systemProperty = annotation.get(); + String actualValue = System.getProperty(systemProperty.name()); + + if (systemProperty.value().equals(actualValue)) { + return ConditionEvaluationResult.enabled("System property matches"); + } else { + return ConditionEvaluationResult.disabled( + String.format("System property [%s] does not match expected value [%s]", + systemProperty.name(), systemProperty.value())); + } + } + + return ConditionEvaluationResult.enabled("No system property condition"); + } +} + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(SystemPropertyCondition.class) +@interface SystemProperty { + String name(); + String value(); +} + +class ConditionalTest { + + @Test + @SystemProperty(name = "env", value = "test") + void testOnlyInTestEnvironment() { + // Only runs when system property env=test + assertTrue(true); + } +} +``` + +### Test Instance Extensions + +Control test instance creation and lifecycle. + +```java { .api } +/** + * Create test instances + */ +interface TestInstanceFactory extends Extension { + /** + * Create test instance + */ + Object createTestInstance(TestInstanceFactoryContext factoryContext, ExtensionContext extensionContext) + throws TestInstantiationException; +} + +/** + * Test instance factory context + */ +interface TestInstanceFactoryContext { + Class getTestClass(); + Optional getOuterInstance(); +} + +/** + * Callback before test instance construction + */ +interface TestInstancePreConstructCallback extends Extension { + void preConstructTestInstance(TestInstancePreConstructContext context, ExtensionContext extensionContext); +} + +/** + * Process test instance after construction + */ +interface TestInstancePostProcessor extends Extension { + void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception; +} + +/** + * Callback before test instance destruction + */ +interface TestInstancePreDestroyCallback extends Extension { + void preDestroyTestInstance(ExtensionContext context) throws Exception; +} +``` + +**Usage Example:** + +```java +class DependencyInjectionExtension implements TestInstancePostProcessor { + + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception { + Class testClass = testInstance.getClass(); + + for (Field field : testClass.getDeclaredFields()) { + if (field.isAnnotationPresent(Inject.class)) { + field.setAccessible(true); + field.set(testInstance, createDependency(field.getType())); + } + } + } + + private Object createDependency(Class type) { + // Create dependency instance + if (type == UserService.class) { + return new UserService(); + } + return null; + } +} + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@interface Inject { +} + +@ExtendWith(DependencyInjectionExtension.class) +class ServiceTest { + + @Inject + private UserService userService; + + @Test + void testWithInjectedService() { + assertNotNull(userService); + // Use injected service + } +} +``` + +### Exception Handling Extensions + +Handle test execution exceptions. + +```java { .api } +/** + * Handle exceptions thrown during test execution + */ +interface TestExecutionExceptionHandler extends Extension { + /** + * Handle test execution exception + */ + void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable; +} + +/** + * Callback before test interruption + */ +interface PreInterruptCallback extends Extension { + /** + * Called before test thread is interrupted + */ + void preInterrupt(PreInterruptContext context, ExtensionContext extensionContext) throws Exception; +} + +/** + * Pre-interrupt context information + */ +interface PreInterruptContext { + Thread getThreadToInterrupt(); + Optional getReason(); +} + +/** + * Watch test execution and results + */ +interface TestWatcher extends Extension { + /** + * Called when test is disabled + */ + default void testDisabled(ExtensionContext context, Optional reason) {} + + /** + * Called when test succeeds + */ + default void testSuccessful(ExtensionContext context) {} + + /** + * Called when test is aborted + */ + default void testAborted(ExtensionContext context, Throwable cause) {} + + /** + * Called when test fails + */ + default void testFailed(ExtensionContext context, Throwable cause) {} +} + +/** + * Intercept method invocations + */ +interface InvocationInterceptor extends Extension { + /** + * Intercept test method invocation + */ + default void interceptTestMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + invocation.proceed(); + } + + /** + * Intercept test class constructor invocation + */ + default T interceptTestClassConstructor(Invocation invocation, + ReflectiveInvocationContext> invocationContext, + ExtensionContext extensionContext) throws Throwable { + return invocation.proceed(); + } + + /** + * Intercept BeforeAll method invocation + */ + default void interceptBeforeAllMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + invocation.proceed(); + } + + /** + * Intercept BeforeEach method invocation + */ + default void interceptBeforeEachMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + invocation.proceed(); + } + + /** + * Intercept AfterEach method invocation + */ + default void interceptAfterEachMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + invocation.proceed(); + } + + /** + * Intercept AfterAll method invocation + */ + default void interceptAfterAllMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + invocation.proceed(); + } +} +``` + +**Usage Example:** + +```java +class RetryExtension implements TestExecutionExceptionHandler { + + @Override + public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { + Optional retryAnnotation = context.getElement() + .map(element -> element.getAnnotation(Retry.class)); + + if (retryAnnotation.isPresent()) { + int maxRetries = retryAnnotation.get().value(); + ExtensionContext.Store store = getStore(context); + int retryCount = store.getOrComputeIfAbsent("retryCount", key -> 0, Integer.class); + + if (retryCount < maxRetries) { + store.put("retryCount", retryCount + 1); + // Retry the test by not re-throwing the exception + return; + } + } + + // Re-throw if no retry or max retries reached + throw throwable; + } + + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore(ExtensionContext.Namespace.create(getClass(), context.getRequiredTestMethod())); + } +} + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(RetryExtension.class) +@interface Retry { + int value() default 3; +} + +class FlakeyTest { + + @Test + @Retry(5) + void testThatMightFail() { + if (Math.random() < 0.7) { + throw new RuntimeException("Random failure"); + } + assertTrue(true); + } +} +``` + +### Extension Context and Store + +Access test context and store data across extension callbacks. + +```java { .api } +/** + * Extension execution context + */ +interface ExtensionContext { + /** + * Get parent context + */ + Optional getParent(); + + /** + * Get root context + */ + ExtensionContext getRoot(); + + /** + * Get unique ID + */ + String getUniqueId(); + + /** + * Get display name + */ + String getDisplayName(); + + /** + * Get all tags + */ + Set getTags(); + + /** + * Get annotated element (class or method) + */ + Optional getElement(); + + /** + * Get test class + */ + Optional> getTestClass(); + + /** + * Get required test class (throws if not present) + */ + Class getRequiredTestClass(); + + /** + * Get test instance lifecycle + */ + Optional getTestInstanceLifecycle(); + + /** + * Get test instance (may be null for static methods) + */ + Optional getTestInstance(); + + /** + * Get all test instances for nested tests + */ + Optional getTestInstances(); + + /** + * Get test method + */ + Optional getTestMethod(); + + /** + * Get required test method (throws if not present) + */ + Method getRequiredTestMethod(); + + /** + * Get execution exception if test failed + */ + Optional getExecutionException(); + + /** + * Get configuration parameter + */ + Optional getConfigurationParameter(String key); + + /** + * Get store for sharing data + */ + Store getStore(Namespace namespace); + + /** + * Publish entry to test report + */ + void publishReportEntry(Map map); + void publishReportEntry(String key, String value); + + /** + * Store namespace for organizing data + */ + class Namespace { + static Namespace create(Object... parts); + static final Namespace GLOBAL; + } + + /** + * Key-value store for extension data + */ + interface Store { + Object get(Object key); + V get(Object key, Class requiredType); + Object getOrComputeIfAbsent(K key, Function defaultCreator); + V getOrComputeIfAbsent(K key, Function defaultCreator, Class requiredType); + void put(Object key, Object value); + Object remove(Object key); + V remove(Object key, Class requiredType); + V getOrDefault(K key, Class requiredType, V defaultValue); + void clear(); + + interface CloseableResource { + void close() throws Throwable; + } + } +} +``` + +**Usage Example:** + +```java +class DataSharingExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback { + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + // Store shared data for all tests + ExtensionContext.Store store = context.getStore(ExtensionContext.Namespace.GLOBAL); + store.put("sharedData", new SharedTestData()); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + // Access test-specific information + String testName = context.getDisplayName(); + Set tags = context.getTags(); + + // Store per-test data + ExtensionContext.Store store = getStore(context); + store.put("testStartTime", System.currentTimeMillis()); + + System.out.printf("Starting test: %s with tags: %s%n", testName, tags); + } + + @Override + public void afterAll(ExtensionContext context) throws Exception { + // Cleanup shared data + ExtensionContext.Store store = context.getStore(ExtensionContext.Namespace.GLOBAL); + store.remove("sharedData"); + } + + private ExtensionContext.Store getStore(ExtensionContext context) { + return context.getStore(ExtensionContext.Namespace.create(getClass(), context.getRequiredTestMethod())); + } +} +``` + +## Additional Types + +### Invocation and Context Types + +Types used with InvocationInterceptor and other advanced extension features. + +```java { .api } +/** + * Represents an invocation that can be proceeded + */ +interface Invocation { + /** + * Proceed with the invocation + */ + T proceed() throws Throwable; + + /** + * Skip the invocation + */ + void skip(); +} + +/** + * Context for reflective invocations + */ +interface ReflectiveInvocationContext { + /** + * Get the executable being invoked (Constructor or Method) + */ + T getExecutable(); + + /** + * Get the arguments for the invocation + */ + List getArguments(); + + /** + * Get the target instance (null for static methods/constructors) + */ + Optional getTarget(); +} + +/** + * Test instances hierarchy for nested tests + */ +interface TestInstances { + /** + * Get the innermost (most nested) test instance + */ + Object getInnermostInstance(); + + /** + * Get all test instances from outermost to innermost + */ + List getEnclosingInstances(); + + /** + * Get all test instances (enclosing + innermost) + */ + List getAllInstances(); + + /** + * Find test instance of specific type + */ + Optional findInstance(Class requiredType); +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/index.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/index.md new file mode 100644 index 000000000..db3a03d37 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/index.md @@ -0,0 +1,249 @@ +# JUnit Jupiter + +JUnit Jupiter is the new programming and extension model for JUnit 5, providing a comprehensive testing framework for Java applications. As an aggregator module, it combines the core JUnit Jupiter API, parameterized test support, and the Jupiter test engine to deliver a unified, modern testing experience with advanced features like nested tests, dynamic tests, custom extensions, and parallel execution. + +## Package Information + +- **Package Name**: org.junit.jupiter:junit-jupiter +- **Package Type**: Maven +- **Language**: Java +- **Installation**: Add to Maven `pom.xml`: + +```xml + + org.junit.jupiter + junit-jupiter + 5.12.2 + test + +``` + +Or Gradle `build.gradle`: + +```groovy +testImplementation 'org.junit.jupiter:junit-jupiter:5.12.2' +``` + +## Core Imports + +```java +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.*; +``` + +Common static imports for assertions: + +```java +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; +``` + +## Basic Usage + +```java +import org.junit.jupiter.api.*; +import static org.junit.jupiter.api.Assertions.*; + +class CalculatorTest { + + @Test + @DisplayName("Addition should work correctly") + void testAddition() { + Calculator calc = new Calculator(); + assertEquals(5, calc.add(2, 3)); + assertNotNull(calc); + } + + @BeforeEach + void setUp() { + // Setup before each test + System.out.println("Setting up test"); + } + + @AfterEach + void tearDown() { + // Cleanup after each test + System.out.println("Cleaning up test"); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 4, 5}) + void testMultipleValues(int value) { + assertTrue(value > 0); + } +} +``` + +## Architecture + +JUnit Jupiter is built around several key components: + +- **Test API**: Core annotations and interfaces for writing tests (`@Test`, `@BeforeEach`, etc.) +- **Assertion Engine**: Comprehensive assertion methods with descriptive failure messages +- **Extension Model**: Powerful extension system for custom behavior and integrations +- **Test Engine**: Runtime execution engine that discovers and runs tests +- **Parameter Resolution**: Dependency injection system for test methods and constructors +- **Conditional Execution**: Rich set of conditions for enabling/disabling tests based on environment + +## Capabilities + +### Core Testing API + +Essential testing annotations, lifecycle methods, and basic test structure. Provides the foundation for writing JUnit 5 tests with modern Java features. + +```java { .api } +@Test +@BeforeAll +@BeforeEach +@AfterEach +@AfterAll +@DisplayName(String value) +@Nested +@Disabled(String reason) +@Timeout(long value, TimeUnit unit) +``` + +[Core Testing](./core-testing.md) + +### Assertions and Assumptions + +Comprehensive assertion methods for verifying test conditions and conditional test execution based on assumptions. + +```java { .api } +// Core assertions +static void assertEquals(Object expected, Object actual); +static void assertTrue(boolean condition); +static void assertThrows(Class expectedType, Executable executable); +static void assertAll(Executable... executables); + +// Assumptions +static void assumeTrue(boolean assumption); +static void assumingThat(boolean assumption, Executable executable); +``` + +[Assertions and Assumptions](./assertions.md) + +### Parameterized Tests + +Advanced parameterized testing with multiple data sources, argument conversion, and aggregation for data-driven test scenarios. + +```java { .api } +@ParameterizedTest +@ValueSource(ints = {1, 2, 3}) +@CsvSource({"1,John", "2,Jane"}) +@MethodSource("argumentProvider") +void parameterizedTest(int value, String name); +``` + +[Parameterized Tests](./parameterized-tests.md) + +### Extensions and Lifecycle + +Powerful extension model for customizing test behavior, dependency injection, and integrating with external frameworks. + +```java { .api } +@ExtendWith(MyExtension.class) +@RegisterExtension +static MyExtension extension = new MyExtension(); + +interface Extension { } +interface BeforeAllCallback extends Extension; +interface ParameterResolver extends Extension; +``` + +[Extensions](./extensions.md) + +### Conditional Execution + +Rich set of conditions for controlling test execution based on operating system, JRE version, system properties, and custom conditions. + +```java { .api } +@EnabledOnOs(OS.LINUX) +@DisabledOnJre(JRE.JAVA_8) +@EnabledIfSystemProperty(named = "env", matches = "prod") +@EnabledIf("customCondition") +``` + +[Conditional Execution](./conditional-execution.md) + +### Dynamic Tests + +Runtime test generation and nested test organization for complex test scenarios and hierarchical test structure. + +```java { .api } +@TestFactory +Stream dynamicTests(); + +static DynamicTest dynamicTest(String displayName, Executable executable); +static DynamicContainer dynamicContainer(String displayName, Stream children); +``` + +[Dynamic Tests](./dynamic-tests.md) + +### Parallel Execution and Resource Management + +Configuration for parallel test execution, resource locking, and temporary file management for performance optimization. + +```java { .api } +@Execution(ExecutionMode.CONCURRENT) +@ResourceLock("database") +@TempDir +Path tempDirectory; +``` + +[Parallel Execution](./parallel-execution.md) + +## Types + +### Core Test Interfaces + +```java { .api } +interface TestInfo { + String getDisplayName(); + Set getTags(); + Optional> getTestClass(); + Optional getTestMethod(); +} + +interface TestReporter { + void publishEntry(Map map); + void publishEntry(String key, String value); +} + +interface RepetitionInfo { + int getCurrentRepetition(); + int getTotalRepetitions(); +} +``` + +### Assertion Utilities + +```java { .api } +class AssertionFailureBuilder { + static AssertionFailureBuilder assertionFailure(); + AssertionFailureBuilder message(String message); + AssertionFailureBuilder expected(Object expected); + AssertionFailureBuilder actual(Object actual); + AssertionFailedError build(); +} +``` + +### Functional Interfaces + +```java { .api } +@FunctionalInterface +interface Executable { + void execute() throws Throwable; +} + +@FunctionalInterface +interface ThrowingSupplier { + T get() throws Throwable; +} + +@FunctionalInterface +interface ThrowingConsumer { + void accept(T t) throws Throwable; +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parallel-execution.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parallel-execution.md new file mode 100644 index 000000000..39cd9984e --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parallel-execution.md @@ -0,0 +1,536 @@ +# Parallel Execution and Resource Management + +Configuration for parallel test execution, resource locking, and temporary file management. JUnit Jupiter provides fine-grained control over test concurrency and resource access. + +## Imports + +```java +import org.junit.jupiter.api.parallel.*; +import org.junit.jupiter.api.io.TempDir; +import java.nio.file.Path; +import static org.junit.jupiter.api.Assertions.*; +``` + +## Capabilities + +### Parallel Execution Configuration + +Control concurrent execution of tests and test classes. + +```java { .api } +/** + * Configure parallel execution mode for tests + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Execution { + /** + * Execution mode for this test or test class + */ + ExecutionMode value(); +} + +/** + * Execution mode enumeration + */ +enum ExecutionMode { + /** + * Execute in same thread as parent + */ + SAME_THREAD, + + /** + * Execute concurrently with other tests (if parallel execution enabled) + */ + CONCURRENT +} +``` + +**Usage Examples:** + +```java +// Enable concurrent execution for entire test class +@Execution(ExecutionMode.CONCURRENT) +class ParallelTest { + + @Test + void test1() { + // Runs concurrently with other tests + performIndependentOperation(); + } + + @Test + void test2() { + // Runs concurrently with other tests + performAnotherIndependentOperation(); + } + + @Test + @Execution(ExecutionMode.SAME_THREAD) + void sequentialTest() { + // Runs sequentially despite class-level concurrent setting + performSequentialOperation(); + } +} + +// Mixed execution modes +class MixedExecutionTest { + + @Test + @Execution(ExecutionMode.CONCURRENT) + void concurrentTest1() { + // Runs concurrently + } + + @Test + @Execution(ExecutionMode.CONCURRENT) + void concurrentTest2() { + // Runs concurrently + } + + @Test + void defaultTest() { + // Uses default execution mode + } +} +``` + +### Test Isolation + +Force sequential execution for tests that require isolation. + +```java { .api } +/** + * Force sequential execution in separate classloader + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface Isolated { +} +``` + +**Usage Example:** + +```java +@Isolated +class IsolatedTest { + + @Test + void testThatModifiesGlobalState() { + System.setProperty("test.mode", "isolated"); + // Test runs in isolation + } + + @Test + void anotherIsolatedTest() { + // Also runs in isolation + } +} + +class RegularTest { + + @Test + @Isolated + void isolatedMethod() { + // Only this method runs in isolation + } + + @Test + void regularMethod() { + // Regular execution + } +} +``` + +### Resource Locking + +Coordinate access to shared resources across concurrent tests. + +```java { .api } +/** + * Lock access to a shared resource + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(ResourceLocks.class) +@interface ResourceLock { + /** + * Resource identifier + */ + String value(); + + /** + * Access mode for the resource + */ + ResourceAccessMode mode() default ResourceAccessMode.READ_WRITE; + + /** + * Target level for the lock + */ + ResourceLockTarget target() default ResourceLockTarget.METHOD; +} + +/** + * Container for multiple resource locks + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface ResourceLocks { + ResourceLock[] value(); +} + +/** + * Resource access mode + */ +enum ResourceAccessMode { + /** + * Exclusive read-write access + */ + READ_WRITE, + + /** + * Shared read-only access + */ + READ +} + +/** + * Resource lock target level + */ +enum ResourceLockTarget { + /** + * Lock applies to individual method + */ + METHOD, + + /** + * Lock applies to entire class + */ + CLASS +} +``` + +**Usage Examples:** + +```java +class ResourceLockTest { + + @Test + @ResourceLock("database") + void testDatabaseWrite() { + // Exclusive access to database resource + database.insert("test data"); + } + + @Test + @ResourceLock(value = "database", mode = ResourceAccessMode.READ) + void testDatabaseRead1() { + // Shared read access - can run concurrently with other read tests + String data = database.select("test data"); + assertNotNull(data); + } + + @Test + @ResourceLock(value = "database", mode = ResourceAccessMode.READ) + void testDatabaseRead2() { + // Shared read access - can run concurrently with testDatabaseRead1 + int count = database.count(); + assertTrue(count >= 0); + } + + @Test + @ResourceLocks({ + @ResourceLock("database"), + @ResourceLock("filesystem") + }) + void testMultipleResources() { + // Requires exclusive access to both database and filesystem + database.backup("/tmp/backup"); + } +} + +@ResourceLock(value = "system-properties", target = ResourceLockTarget.CLASS) +class SystemPropertiesTest { + + @Test + void testSystemProperty1() { + System.setProperty("test.prop", "value1"); + // Entire class has exclusive access to system properties + } + + @Test + void testSystemProperty2() { + System.setProperty("test.prop", "value2"); + // Sequential execution guaranteed + } +} +``` + +### Standard Resources + +Pre-defined resource identifiers for common shared resources. + +```java { .api } +/** + * Standard resource constants + */ +class Resources { + /** + * Global resource lock + */ + public static final String GLOBAL = "GLOBAL"; + + /** + * Java system properties + */ + public static final String SYSTEM_PROPERTIES = "SYSTEM_PROPERTIES"; + + /** + * Java system environment + */ + public static final String SYSTEM_ENVIRONMENT = "SYSTEM_ENVIRONMENT"; + + /** + * Standard input/output streams + */ + public static final String SYSTEM_OUT = "SYSTEM_OUT"; + public static final String SYSTEM_ERR = "SYSTEM_ERR"; + public static final String SYSTEM_IN = "SYSTEM_IN"; + + /** + * Java locale settings + */ + public static final String LOCALE = "LOCALE"; + + /** + * Java time zone settings + */ + public static final String TIME_ZONE = "TIME_ZONE"; +} +``` + +**Usage Examples:** + +```java +class StandardResourcesTest { + + @Test + @ResourceLock(Resources.SYSTEM_PROPERTIES) + void testWithSystemProperties() { + String original = System.getProperty("user.dir"); + System.setProperty("user.dir", "/tmp"); + + // Test with modified system property + assertEquals("/tmp", System.getProperty("user.dir")); + + // Restore + System.setProperty("user.dir", original); + } + + @Test + @ResourceLock(Resources.SYSTEM_OUT) + void testWithSystemOut() { + PrintStream originalOut = System.out; + ByteArrayOutputStream capturedOut = new ByteArrayOutputStream(); + System.setOut(new PrintStream(capturedOut)); + + System.out.println("Test output"); + assertEquals("Test output\n", capturedOut.toString()); + + System.setOut(originalOut); + } + + @Test + @ResourceLock(Resources.LOCALE) + void testWithLocale() { + Locale original = Locale.getDefault(); + Locale.setDefault(Locale.FRENCH); + + // Test with French locale + assertEquals(Locale.FRENCH, Locale.getDefault()); + + Locale.setDefault(original); + } +} +``` + +### Custom Resource Locks Provider + +Programmatically provide resource locks based on test context. + +```java { .api } +/** + * Provides resource locks programmatically + */ +interface ResourceLocksProvider { + /** + * Provide resource locks for the given extension context + */ + Set provideForClass(ExtensionContext context); + Set provideForNestedClass(ExtensionContext context); + Set provideForMethod(ExtensionContext context); + + /** + * Resource lock representation + */ + interface Lock { + String getKey(); + ResourceAccessMode getAccessMode(); + } +} +``` + +### Temporary Directory Support + +Automatic temporary directory creation and cleanup for tests. + +```java { .api } +/** + * Inject temporary directory into test method or field + */ +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@interface TempDir { + /** + * Cleanup mode for temporary directory + */ + CleanupMode cleanup() default CleanupMode.DEFAULT; + + /** + * Factory for creating temporary directories + */ + Class factory() default TempDirFactory.Standard.class; +} + +/** + * Cleanup mode for temporary directories + */ +enum CleanupMode { + /** + * Use default cleanup behavior + */ + DEFAULT, + + /** + * Never clean up temporary directories + */ + NEVER, + + /** + * Always clean up temporary directories + */ + ALWAYS, + + /** + * Clean up on success, keep on failure + */ + ON_SUCCESS +} + +/** + * Factory for creating temporary directories + */ +interface TempDirFactory { + /** + * Create temporary directory + */ + Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException; + + /** + * Standard temporary directory factory + */ + class Standard implements TempDirFactory { + @Override + public Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException { + return Files.createTempDirectory("junit"); + } + } +} +``` + +**Usage Examples:** + +```java +class TempDirTest { + + @TempDir + Path sharedTempDir; + + @Test + void testWithSharedTempDir() throws IOException { + Path file = sharedTempDir.resolve("test.txt"); + Files.write(file, "test content".getBytes()); + + assertTrue(Files.exists(file)); + assertEquals("test content", Files.readString(file)); + } + + @Test + void testWithMethodTempDir(@TempDir Path tempDir) throws IOException { + // Each test method gets its own temp directory + assertNotEquals(sharedTempDir, tempDir); + + Path file = tempDir.resolve("method-test.txt"); + Files.createFile(file); + assertTrue(Files.exists(file)); + } + + @Test + void testWithCustomCleanup(@TempDir(cleanup = CleanupMode.NEVER) Path persistentDir) throws IOException { + // This directory won't be cleaned up automatically + Path file = persistentDir.resolve("persistent.txt"); + Files.write(file, "This file will persist".getBytes()); + + System.out.println("Persistent dir: " + persistentDir); + } + + @Test + void testWithCustomFactory(@TempDir(factory = CustomTempDirFactory.class) Path customDir) { + // Directory created by custom factory + assertTrue(customDir.toString().contains("custom")); + } +} + +class CustomTempDirFactory implements TempDirFactory { + @Override + public Path createTempDirectory(AnnotatedElement annotatedElement, ExtensionContext extensionContext) throws IOException { + return Files.createTempDirectory("custom-junit-" + extensionContext.getDisplayName()); + } +} +``` + +### Configuration Properties + +Configure parallel execution behavior through system properties or configuration files. + +**Key Configuration Properties:** + +```properties +# Enable parallel execution +junit.jupiter.execution.parallel.enabled=true + +# Default execution mode +junit.jupiter.execution.parallel.mode.default=concurrent + +# Class-level execution mode +junit.jupiter.execution.parallel.mode.classes.default=concurrent + +# Parallelism strategy +junit.jupiter.execution.parallel.config.strategy=dynamic +# or fixed with custom thread count +junit.jupiter.execution.parallel.config.strategy=fixed +junit.jupiter.execution.parallel.config.fixed.parallelism=4 + +# Dynamic parallelism factor +junit.jupiter.execution.parallel.config.dynamic.factor=2.0 +``` + +**Usage in junit-platform.properties:** + +```properties +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.default=concurrent +junit.jupiter.execution.parallel.mode.classes.default=same_thread +junit.jupiter.execution.parallel.config.strategy=dynamic +junit.jupiter.execution.parallel.config.dynamic.factor=1.5 +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parameterized-tests.md b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parameterized-tests.md new file mode 100644 index 000000000..04389b1f1 --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/docs/parameterized-tests.md @@ -0,0 +1,902 @@ +# Parameterized Tests + +Advanced parameterized testing capabilities that allow running the same test logic with different sets of arguments. JUnit Jupiter provides multiple ways to supply test arguments with support for custom conversion and aggregation. + +## Imports + +```java +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.*; +import org.junit.jupiter.params.aggregator.*; +import org.junit.jupiter.params.converter.*; +import static org.junit.jupiter.api.Assertions.*; +``` + +## Capabilities + +### Parameterized Test Annotation + +Core annotation for defining parameterized tests. + +```java { .api } +/** + * Marks a method as a parameterized test with multiple argument sources + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@interface ParameterizedTest { + /** + * Custom name pattern for parameterized test invocations + */ + String name() default "[{index}] {arguments}"; + + /** + * How to handle argument count mismatches + */ + ArgumentCountValidationMode argumentCountValidationMode() default ArgumentCountValidationMode.STRICT; +} + +enum ArgumentCountValidationMode { + STRICT, // Fail if parameter count doesn't match + LENIENT, // Allow missing parameters (null values) + IGNORE // Ignore extra arguments +} +``` + +**Basic Usage:** + +```java +@ParameterizedTest +@ValueSource(ints = {1, 2, 3}) +void testWithValueSource(int argument) { + assertTrue(argument > 0); +} + +@ParameterizedTest(name = "Run {index}: testing with value {0}") +@ValueSource(strings = {"apple", "banana", "cherry"}) +void testWithCustomName(String fruit) { + assertNotNull(fruit); + assertTrue(fruit.length() > 3); +} +``` + +### Value Sources + +Simple argument sources for primitive types and strings. + +```java { .api } +/** + * Array of literal values as arguments + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(ValueArgumentsProvider.class) +@interface ValueSource { + short[] shorts() default {}; + byte[] bytes() default {}; + int[] ints() default {}; + long[] longs() default {}; + float[] floats() default {}; + double[] doubles() default {}; + char[] chars() default {}; + boolean[] booleans() default {}; + String[] strings() default {}; + Class[] classes() default {}; +} + +/** + * Container for multiple value sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface ValueSources { + ValueSource[] value(); +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@ValueSource(ints = {1, 2, 3, 4, 5}) +void testNumbers(int number) { + assertTrue(number > 0 && number < 6); +} + +@ParameterizedTest +@ValueSource(strings = {"", " "}) +void testBlankStrings(String input) { + assertTrue(input.isBlank()); +} + +@ParameterizedTest +@ValueSource(booleans = {true, false}) +void testBooleans(boolean value) { + // Test both true and false cases + assertNotNull(Boolean.valueOf(value)); +} + +@ParameterizedTest +@ValueSource(classes = {String.class, Integer.class, List.class}) +void testClasses(Class clazz) { + assertNotNull(clazz); + assertNotNull(clazz.getName()); +} +``` + +### Null and Empty Sources + +Special argument sources for null and empty values. + +```java { .api } +/** + * Provides a single null argument + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(NullArgumentsProvider.class) +@interface NullSource { +} + +/** + * Provides empty values for strings, lists, sets, maps, and primitive arrays + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(EmptyArgumentsProvider.class) +@interface EmptySource { +} + +/** + * Combines null and empty sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@NullSource +@EmptySource +@interface NullAndEmptySource { +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@NullSource +@ValueSource(strings = {"", " ", "valid"}) +void testStringValidation(String input) { + // Test with null, empty, blank, and valid strings + String result = StringUtils.clean(input); + // Assert based on input type +} + +@ParameterizedTest +@NullAndEmptySource +@ValueSource(strings = {"apple", "banana"}) +void testStringProcessing(String input) { + // Test null, empty, and actual values + String processed = processString(input); + if (input == null || input.isEmpty()) { + assertEquals("default", processed); + } else { + assertNotEquals("default", processed); + } +} + +@ParameterizedTest +@EmptySource +@ValueSource(ints = {1, 2, 3}) +void testIntArrays(int[] array) { + // Test with empty array and arrays with values + assertNotNull(array); +} +``` + +### Enum Sources + +Arguments from enum values with filtering options. + +```java { .api } +/** + * Provides enum values as arguments + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(EnumArgumentsProvider.class) +@interface EnumSource { + /** + * Enum class to get values from + */ + Class> value(); + + /** + * Enum constant names to include/exclude + */ + String[] names() default {}; + + /** + * Whether to include or exclude specified names + */ + Mode mode() default Mode.INCLUDE; + + enum Mode { + INCLUDE, // Include only specified names + EXCLUDE, // Exclude specified names + MATCH_ALL, // Include names matching all patterns + MATCH_ANY // Include names matching any pattern + } +} + +/** + * Container for multiple enum sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface EnumSources { + EnumSource[] value(); +} +``` + +**Usage Examples:** + +```java +enum Color { + RED, GREEN, BLUE, YELLOW, PURPLE +} + +@ParameterizedTest +@EnumSource(Color.class) +void testAllColors(Color color) { + assertNotNull(color); + assertTrue(color.name().length() > 2); +} + +@ParameterizedTest +@EnumSource(value = Color.class, names = {"RED", "BLUE"}) +void testSpecificColors(Color color) { + assertTrue(color == Color.RED || color == Color.BLUE); +} + +@ParameterizedTest +@EnumSource(value = Color.class, names = {"YELLOW"}, mode = EnumSource.Mode.EXCLUDE) +void testAllColorsExceptYellow(Color color) { + assertNotEquals(Color.YELLOW, color); +} + +@ParameterizedTest +@EnumSource(value = Color.class, names = {"^B.*"}, mode = EnumSource.Mode.MATCH_ALL) +void testColorsStartingWithB(Color color) { + assertTrue(color.name().startsWith("B")); +} +``` + +### CSV Sources + +Arguments from CSV data, either inline or from files. + +```java { .api } +/** + * Provides CSV data as arguments + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(CsvArgumentsProvider.class) +@interface CsvSource { + /** + * CSV records as string array + */ + String[] value(); + + /** + * Column delimiter character + */ + char delimiter() default ','; + + /** + * String to represent null values + */ + String nullValues() default ""; + + /** + * Quote character for escaping + */ + char quoteCharacter() default '"'; + + /** + * How to handle empty values + */ + EmptyValue emptyValue() default EmptyValue.EMPTY_STRING; + + /** + * Whether to ignore leading/trailing whitespace + */ + boolean ignoreLeadingAndTrailingWhitespace() default true; + + enum EmptyValue { + EMPTY_STRING, // Empty string "" + NULL_REFERENCE // null + } +} + +/** + * Container for multiple CSV sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface CsvSources { + CsvSource[] value(); +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@CsvSource({ + "apple, 1", + "banana, 2", + "'lemon, lime', 3" +}) +void testWithCsvSource(String fruit, int rank) { + assertNotNull(fruit); + assertTrue(rank > 0); +} + +@ParameterizedTest +@CsvSource(value = { + "John:25:Engineer", + "Jane:30:Manager", + "Bob:35:Developer" +}, delimiter = ':') +void testPersonData(String name, int age, String role) { + assertNotNull(name); + assertTrue(age > 0); + assertNotNull(role); +} + +@ParameterizedTest +@CsvSource(value = { + "test, NULL, 42", + "example, , 0" +}, nullValues = "NULL") +void testWithNullValues(String str, String nullableStr, int number) { + assertNotNull(str); + // nullableStr might be null + assertTrue(number >= 0); +} +``` + +### CSV File Sources + +Arguments from external CSV files. + +```java { .api } +/** + * Provides CSV data from files as arguments + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(CsvFileArgumentsProvider.class) +@interface CsvFileSource { + /** + * CSV file resources (classpath relative) + */ + String[] resources() default {}; + + /** + * CSV files (file system paths) + */ + String[] files() default {}; + + /** + * Character encoding for files + */ + String encoding() default "UTF-8"; + + /** + * Line separator for files + */ + String lineSeparator() default "\n"; + + /** + * Column delimiter character + */ + char delimiter() default ','; + + /** + * String to represent null values + */ + String nullValues() default ""; + + /** + * Quote character for escaping + */ + char quoteCharacter() default '"'; + + /** + * How to handle empty values + */ + CsvSource.EmptyValue emptyValue() default CsvSource.EmptyValue.EMPTY_STRING; + + /** + * Whether to ignore leading/trailing whitespace + */ + boolean ignoreLeadingAndTrailingWhitespace() default true; + + /** + * Number of header lines to skip + */ + int numLinesToSkip() default 0; +} + +/** + * Container for multiple CSV file sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface CsvFileSources { + CsvFileSource[] value(); +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@CsvFileSource(resources = "/test-data.csv", numLinesToSkip = 1) +void testWithCsvFileSource(String name, int age, String city) { + assertNotNull(name); + assertTrue(age > 0); + assertNotNull(city); +} + +@ParameterizedTest +@CsvFileSource(files = "src/test/resources/users.csv", delimiter = ';') +void testUserData(String username, String email, boolean active) { + assertNotNull(username); + assertTrue(email.contains("@")); + // active can be true or false +} +``` + +### Method Sources + +Arguments from static methods. + +```java { .api } +/** + * Provides arguments from static methods + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(MethodArgumentsProvider.class) +@interface MethodSource { + /** + * Method names that provide arguments + * If empty, uses test method name + */ + String[] value() default {}; +} + +/** + * Container for multiple method sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface MethodSources { + MethodSource[] value(); +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@MethodSource("stringProvider") +void testWithMethodSource(String argument) { + assertNotNull(argument); +} + +static Stream stringProvider() { + return Stream.of("apple", "banana", "cherry"); +} + +@ParameterizedTest +@MethodSource("personProvider") +void testPersons(Person person) { + assertNotNull(person.getName()); + assertTrue(person.getAge() > 0); +} + +static Stream personProvider() { + return Stream.of( + new Person("John", 25), + new Person("Jane", 30), + new Person("Bob", 35) + ); +} + +@ParameterizedTest +@MethodSource("argumentProvider") +void testWithMultipleArguments(int number, String text, boolean flag) { + assertTrue(number > 0); + assertNotNull(text); + // flag can be any boolean value +} + +static Stream argumentProvider() { + return Stream.of( + Arguments.of(1, "first", true), + Arguments.of(2, "second", false), + Arguments.of(3, "third", true) + ); +} +``` + +### Field Sources + +Arguments from static fields. + +```java { .api } +/** + * Provides arguments from static fields + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(FieldArgumentsProvider.class) +@interface FieldSource { + /** + * Field names that provide arguments + * If empty, uses test method name + */ + String[] value() default {}; +} + +/** + * Container for multiple field sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface FieldSources { + FieldSource[] value(); +} +``` + +**Usage Examples:** + +```java +static List fruits = Arrays.asList("apple", "banana", "cherry"); + +@ParameterizedTest +@FieldSource("fruits") +void testWithFieldSource(String fruit) { + assertNotNull(fruit); + assertTrue(fruit.length() > 3); +} + +static Stream testData = Stream.of( + Arguments.of(1, "one"), + Arguments.of(2, "two"), + Arguments.of(3, "three") +); + +@ParameterizedTest +@FieldSource("testData") +void testWithArgumentsField(int number, String word) { + assertTrue(number > 0); + assertNotNull(word); +} +``` + +### Custom Argument Sources + +Create custom argument providers for complex scenarios. + +```java { .api } +/** + * Custom arguments source annotation + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(CustomArgumentsProvider.class) +@interface ArgumentsSource { + /** + * ArgumentsProvider implementation class + */ + Class value(); +} + +/** + * Container for multiple custom sources + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@interface ArgumentsSources { + ArgumentsSource[] value(); +} + +/** + * Arguments provider interface + */ +interface ArgumentsProvider { + /** + * Provide arguments for parameterized test + */ + Stream provideArguments(ExtensionContext context) throws Exception; +} + +/** + * Base class for annotation-based providers + */ +abstract class AnnotationBasedArgumentsProvider implements ArgumentsProvider { + /** + * Accept annotation for configuration + */ + protected abstract void accept(T annotation); +} +``` + +**Usage Example:** + +```java +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@ArgumentsSource(RandomIntegerProvider.class) +@interface RandomIntegers { + int count() default 10; + int min() default 0; + int max() default 100; +} + +class RandomIntegerProvider extends AnnotationBasedArgumentsProvider { + private int count; + private int min; + private int max; + + @Override + protected void accept(RandomIntegers annotation) { + this.count = annotation.count(); + this.min = annotation.min(); + this.max = annotation.max(); + } + + @Override + public Stream provideArguments(ExtensionContext context) { + Random random = new Random(); + return random.ints(count, min, max) + .mapToObj(Arguments::of); + } +} + +@ParameterizedTest +@RandomIntegers(count = 5, min = 1, max = 10) +void testWithRandomIntegers(int value) { + assertTrue(value >= 1 && value <= 10); +} +``` + +### Argument Conversion + +Convert string arguments to other types automatically or with custom converters. + +```java { .api } +/** + * Custom argument converter annotation + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@interface ConvertWith { + /** + * ArgumentConverter implementation class + */ + Class value(); +} + +/** + * Java time conversion pattern + */ +@Target({ElementType.ANNOTATION_TYPE, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@ConvertWith(JavaTimeArgumentConverter.class) +@interface JavaTimeConversionPattern { + /** + * Pattern for parsing date/time + */ + String value(); +} + +/** + * Argument converter interface + */ +interface ArgumentConverter { + /** + * Convert source argument to target type + */ + T convert(S source, ParameterContext context) throws ArgumentConversionException; +} + +/** + * Simple converter for single argument types + */ +abstract class SimpleArgumentConverter implements ArgumentConverter { + @Override + public final T convert(S source, ParameterContext context) throws ArgumentConversionException { + return convert(source, context.getParameter().getType()); + } + + /** + * Convert source to target type + */ + protected abstract T convert(S source, Class targetType) throws ArgumentConversionException; +} + +/** + * Typed converter with type safety + */ +abstract class TypedArgumentConverter extends SimpleArgumentConverter { + private final Class sourceType; + private final Class targetType; + + protected TypedArgumentConverter(Class sourceType, Class targetType) { + this.sourceType = sourceType; + this.targetType = targetType; + } +} +``` + +**Usage Examples:** + +```java +@ParameterizedTest +@ValueSource(strings = {"2023-01-01", "2023-12-31"}) +void testDates(@JavaTimeConversionPattern("yyyy-MM-dd") LocalDate date) { + assertNotNull(date); + assertEquals(2023, date.getYear()); +} + +class StringToPersonConverter extends TypedArgumentConverter { + protected StringToPersonConverter() { + super(String.class, Person.class); + } + + @Override + protected Person convert(String source, Class targetType) { + String[] parts = source.split(","); + return new Person(parts[0], Integer.parseInt(parts[1])); + } +} + +@ParameterizedTest +@ValueSource(strings = {"John,25", "Jane,30", "Bob,35"}) +void testPersonConversion(@ConvertWith(StringToPersonConverter.class) Person person) { + assertNotNull(person.getName()); + assertTrue(person.getAge() > 0); +} +``` + +### Argument Aggregation + +Aggregate multiple arguments into complex objects. + +```java { .api } +/** + * Custom argument aggregator annotation + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@interface AggregateWith { + /** + * ArgumentsAggregator implementation class + */ + Class value(); +} + +/** + * Arguments aggregator interface + */ +interface ArgumentsAggregator { + /** + * Aggregate arguments into single object + */ + Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) + throws ArgumentsAggregationException; +} + +/** + * Arguments accessor for retrieving individual arguments + */ +interface ArgumentsAccessor { + Object get(int index); + T get(int index, Class requiredType); + Character getCharacter(int index); + Boolean getBoolean(int index); + Byte getByte(int index); + Short getShort(int index); + Integer getInteger(int index); + Long getLong(int index); + Float getFloat(int index); + Double getDouble(int index); + String getString(int index); + int size(); + Object[] toArray(); + List toList(); +} +``` + +**Usage Examples:** + +```java +class PersonAggregator implements ArgumentsAggregator { + @Override + public Object aggregateArguments(ArgumentsAccessor accessor, ParameterContext context) { + return new Person(accessor.getString(0), accessor.getInteger(1)); + } +} + +@ParameterizedTest +@CsvSource({ + "John, 25", + "Jane, 30", + "Bob, 35" +}) +void testPersonAggregation(@AggregateWith(PersonAggregator.class) Person person) { + assertNotNull(person.getName()); + assertTrue(person.getAge() > 0); +} + +@ParameterizedTest +@CsvSource({ + "John, 25, Engineer", + "Jane, 30, Manager", + "Bob, 35, Developer" +}) +void testWithArgumentsAccessor(ArgumentsAccessor arguments) { + String name = arguments.getString(0); + int age = arguments.getInteger(1); + String role = arguments.getString(2); + + Person person = new Person(name, age, role); + assertNotNull(person); +} +``` + +### Arguments Utility + +Utility class for creating argument sets programmatically. + +```java { .api } +/** + * Factory for creating Arguments instances + */ +interface Arguments { + /** + * Create Arguments from array of objects + */ + static Arguments of(Object... arguments); + + /** + * Get arguments as object array + */ + Object[] get(); +} +``` + +**Usage Example:** + +```java +static Stream complexArgumentProvider() { + return Stream.of( + Arguments.of(1, "apple", true, new Person("John", 25)), + Arguments.of(2, "banana", false, new Person("Jane", 30)), + Arguments.of(3, "cherry", true, new Person("Bob", 35)) + ); +} + +@ParameterizedTest +@MethodSource("complexArgumentProvider") +void testComplexArguments(int id, String fruit, boolean active, Person person) { + assertTrue(id > 0); + assertNotNull(fruit); + assertNotNull(person); +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/tile.json b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/tile.json new file mode 100644 index 000000000..dbd26c93b --- /dev/null +++ b/.tessl/tiles/tessl/maven-org-junit-jupiter--junit-jupiter/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/maven-org-junit-jupiter--junit-jupiter", + "version": "5.12.0", + "docs": "docs/index.md", + "describes": "pkg:maven/org.junit.jupiter/junit-jupiter@5.12.2", + "summary": "JUnit Jupiter aggregator module providing a unified API for JUnit 5 testing framework with core API, parameterized tests, and test engine." +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/docs/configuration.md b/.tessl/tiles/tessl/npm-babel--core/docs/configuration.md new file mode 100644 index 000000000..be95693e6 --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/docs/configuration.md @@ -0,0 +1,486 @@ +# Configuration Management + +Babel configuration loading, validation, and management system supporting various config file formats, runtime options, and plugin/preset resolution. Provides both full and partial configuration loading for different use cases. + +## Capabilities + +### Options Loading + +Load and resolve complete Babel configuration from various sources. + +```typescript { .api } +/** + * Load complete Babel options synchronously + * @param opts - Input options to merge with config file settings + * @returns Resolved configuration object or null if no config found + */ +function loadOptionsSync(opts?: InputOptions): ResolvedConfig | null; + +/** + * Load complete Babel options asynchronously + * @param opts - Input options to merge with config file settings + * @returns Promise resolving to resolved configuration or null + */ +function loadOptionsAsync(opts?: InputOptions): Promise; + +/** + * Load complete Babel options with callback (legacy API, deprecated in Babel 8) + * @param opts - Input options to merge with config file settings + * @param callback - Callback function receiving error and resolved config + */ +function loadOptions( + opts: InputOptions, + callback: (err: Error | null, config: ResolvedConfig | null) => void +): void; +function loadOptions( + callback: (err: Error | null, config: ResolvedConfig | null) => void +): void; + +interface ResolvedConfig { + /** Resolved plugins with their options */ + plugins: Array; + /** Resolved presets with their options */ + presets: Array; + /** Parser options */ + parserOpts: ParserOptions; + /** Generator options */ + generatorOpts: GeneratorOptions; + /** All other resolved options */ + [key: string]: any; +} +``` + +**Usage Examples:** + +```typescript +import { loadOptionsSync, loadOptionsAsync } from "@babel/core"; + +// Load configuration from babel.config.js and .babelrc files +const config = loadOptionsSync({ + cwd: "/path/to/project", + filename: "src/app.js", + envName: "production" +}); + +if (config) { + console.log("Plugins:", config.plugins.map(p => p.name)); + console.log("Presets:", config.presets.map(p => p.name)); + console.log("Parser options:", config.parserOpts); +} + +// Override config file settings +const customConfig = loadOptionsSync({ + presets: ["@babel/preset-env"], + plugins: ["@babel/plugin-transform-runtime"], + targets: "> 0.25%, not dead" +}); + +// Async loading +const asyncConfig = await loadOptionsAsync({ + cwd: process.cwd(), + configFile: "./babel.config.json", + envName: process.env.NODE_ENV +}); +``` + +### Partial Configuration + +Load partial configuration for advanced use cases where full resolution isn't needed. + +```typescript { .api } +/** + * Load partial Babel configuration synchronously + * @param opts - Input options for partial resolution + * @returns Partial configuration object or null + */ +function loadPartialConfigSync(opts?: InputOptions): PartialConfig | null; + +/** + * Load partial Babel configuration asynchronously + * @param opts - Input options for partial resolution + * @returns Promise resolving to partial configuration or null + */ +function loadPartialConfigAsync(opts?: InputOptions): Promise; + +/** + * Load partial configuration with callback (legacy API, deprecated in Babel 8) + * @param opts - Input options for partial resolution + * @param callback - Callback function receiving error and partial config + */ +function loadPartialConfig( + opts: InputOptions, + callback: (err: Error | null, config: PartialConfig | null) => void +): void; +function loadPartialConfig( + callback: (err: Error | null, config: PartialConfig | null) => void +): void; + +interface PartialConfig { + /** Resolved options (may be null if no valid config) */ + options: ResolvedConfig | null; + /** Loaded config file information */ + config?: { + filepath: string; + dirname: string; + options: any; + }; + /** Loaded .babelrc file information */ + babelrc?: { + filepath: string; + dirname: string; + options: any; + }; + /** Whether this config ignores the file */ + hasFilesystemConfig(): boolean; +} +``` + +**Usage Examples:** + +```typescript +import { loadPartialConfigSync } from "@babel/core"; + +// Check if a file should be processed +const partialConfig = loadPartialConfigSync({ + filename: "src/components/Button.tsx", + cwd: "/path/to/project" +}); + +if (partialConfig) { + if (partialConfig.hasFilesystemConfig()) { + console.log("File has Babel config"); + + if (partialConfig.config) { + console.log("Config file:", partialConfig.config.filepath); + } + + if (partialConfig.babelrc) { + console.log("Babelrc file:", partialConfig.babelrc.filepath); + } + + // Use resolved options + if (partialConfig.options) { + console.log("Resolved plugins:", partialConfig.options.plugins.length); + } + } else { + console.log("No Babel config found for this file"); + } +} +``` + +### Configuration Items + +Create and manage individual plugin and preset configuration items. + +```typescript { .api } +/** + * Create configuration item synchronously + * @param target - Plugin/preset function, module name, or path + * @param options - Options to pass to the plugin/preset + * @returns Configuration item or null if invalid + */ +function createConfigItemSync( + target: PluginTarget, + options?: ConfigItemOptions +): ConfigItem | null; + +/** + * Create configuration item asynchronously + * @param target - Plugin/preset function, module name, or path + * @param options - Options to pass to the plugin/preset + * @returns Promise resolving to configuration item or null + */ +function createConfigItemAsync( + target: PluginTarget, + options?: ConfigItemOptions +): Promise | null>; + +/** + * Create configuration item with callback (legacy API, deprecated in Babel 8) + * @param target - Plugin/preset function, module name, or path + * @param options - Options to pass to the plugin/preset + * @param callback - Callback function receiving error and config item + */ +function createConfigItem( + target: PluginTarget, + options: ConfigItemOptions, + callback: (err: Error | null, item: ConfigItem | null) => void +): void; + +type PluginTarget = + | string + | PluginFunction + | PresetFunction + | [string, any] + | [PluginFunction, any] + | [PresetFunction, any]; + +interface ConfigItemOptions { + /** Directory context for resolution */ + dirname?: string; + /** Item type: "plugin" or "preset" */ + type?: "plugin" | "preset"; +} + +interface ConfigItem { + /** Resolved plugin/preset function */ + value: T; + /** Configuration options passed to the plugin/preset */ + options: any; + /** Directory where the plugin/preset was resolved */ + dirname: string; + /** Name of the plugin/preset */ + name?: string; + /** Full file path if resolved from file */ + file?: { + request: string; + resolved: string; + }; +} +``` + +**Usage Examples:** + +```typescript +import { createConfigItemSync } from "@babel/core"; + +// Create plugin config item +const pluginItem = createConfigItemSync("@babel/plugin-transform-runtime", { + dirname: "/path/to/project", + type: "plugin" +}); + +if (pluginItem) { + console.log("Plugin name:", pluginItem.name); + console.log("Plugin options:", pluginItem.options); + console.log("Resolved from:", pluginItem.file?.resolved); +} + +// Create preset config item with options +const presetItem = createConfigItemSync( + ["@babel/preset-env", { + targets: "> 0.25%, not dead", + useBuiltIns: "usage", + corejs: 3 + }], + { + dirname: process.cwd(), + type: "preset" + } +); + +// Create from function +const customPlugin = function(babel) { + return { + visitor: { + Identifier(path) { + console.log("Found identifier:", path.node.name); + } + } + }; +}; + +const customItem = createConfigItemSync(customPlugin, { + dirname: __dirname, + type: "plugin" +}); +``` + +## Configuration File Support + +Babel supports various configuration file formats: + +```typescript { .api } +interface ConfigFileOptions { + /** Path to specific config file, or false to disable */ + configFile?: string | false; + /** Enable/disable .babelrc file loading */ + babelrc?: boolean; + /** Root directory for config file search */ + root?: string; + /** Current working directory */ + cwd?: string; + /** Override root mode: "root", "upward", or "upward-optional" */ + rootMode?: "root" | "upward" | "upward-optional"; +} +``` + +**Supported Config Files:** + +- `babel.config.json` - Project-wide configuration +- `babel.config.js` - Project-wide with JavaScript +- `babel.config.mjs` - Project-wide with ES modules +- `babel.config.cjs` - Project-wide with CommonJS +- `.babelrc` - File-relative configuration +- `.babelrc.json` - File-relative JSON +- `.babelrc.js` - File-relative JavaScript +- `package.json` - Babel field in package.json + +**Usage Examples:** + +```typescript +import { loadOptionsSync } from "@babel/core"; + +// Use specific config file +const config1 = loadOptionsSync({ + configFile: "./babel.production.js", + cwd: "/path/to/project" +}); + +// Disable config file loading +const config2 = loadOptionsSync({ + configFile: false, + plugins: ["@babel/plugin-transform-arrow-functions"] +}); + +// Disable .babelrc files +const config3 = loadOptionsSync({ + babelrc: false, + presets: ["@babel/preset-env"] +}); + +// Search from different root +const config4 = loadOptionsSync({ + root: "/different/root", + rootMode: "upward", + filename: "src/app.js" +}); +``` + +## Environment-based Configuration + +Configure Babel behavior based on environment: + +```typescript { .api } +interface EnvironmentOptions { + /** Environment name (defaults to BABEL_ENV || NODE_ENV || "development") */ + envName?: string; + /** Caller metadata for conditional configuration */ + caller?: CallerMetadata; +} + +interface CallerMetadata { + /** Name of the calling tool */ + name: string; + /** Version of the calling tool */ + version?: string; + /** Whether the caller supports ES modules */ + supportsStaticESM?: boolean; + /** Whether the caller supports dynamic imports */ + supportsDynamicImport?: boolean; + /** Whether the caller supports top-level await */ + supportsTopLevelAwait?: boolean; + /** Additional caller-specific properties */ + [key: string]: any; +} +``` + +**Usage Examples:** + +```typescript +import { loadOptionsSync } from "@babel/core"; + +// Load development configuration +const devConfig = loadOptionsSync({ + envName: "development", + caller: { + name: "webpack", + version: "5.0.0", + supportsStaticESM: true + } +}); + +// Load production configuration +const prodConfig = loadOptionsSync({ + envName: "production", + caller: { + name: "rollup", + version: "2.0.0", + supportsDynamicImport: true + } +}); + +// Override environment +process.env.NODE_ENV = "test"; +const testConfig = loadOptionsSync({ + envName: "testing", // Overrides NODE_ENV + filename: "test/example.spec.js" +}); +``` + +## Advanced Configuration Patterns + +### Conditional Configuration + +```javascript +// babel.config.js +module.exports = function(api) { + // Cache configuration based on environment + api.cache.using(() => process.env.NODE_ENV); + + const presets = ["@babel/preset-env"]; + const plugins = []; + + // Add plugins based on environment + if (api.env("development")) { + plugins.push("react-refresh/babel"); + } + + // Add plugins based on caller + if (api.caller(caller => caller?.name === "webpack")) { + plugins.push("@babel/plugin-syntax-dynamic-import"); + } + + return { presets, plugins }; +}; +``` + +### Programmatic Configuration + +```typescript +import { loadOptionsSync, transformSync } from "@babel/core"; + +// Build configuration programmatically +const baseConfig = loadOptionsSync({ + presets: ["@babel/preset-env"], + configFile: false +}); + +// Extend with additional plugins +const extendedConfig = { + ...baseConfig, + plugins: [ + ...baseConfig.plugins, + ["@babel/plugin-transform-runtime", { corejs: 3 }] + ] +}; + +// Use extended configuration +const result = transformSync(code, extendedConfig); +``` + +## Error Handling + +Configuration functions may throw errors for invalid configurations: + +```typescript +import { loadOptionsSync, createConfigItemSync } from "@babel/core"; + +try { + const config = loadOptionsSync({ + plugins: ["non-existent-plugin"] + }); +} catch (error) { + if (error.code === "BABEL_UNKNOWN_PLUGIN") { + console.error("Unknown plugin:", error.message); + } +} + +try { + const item = createConfigItemSync("invalid-plugin", { + dirname: "/nonexistent" + }); +} catch (error) { + console.error("Failed to create config item:", error.message); +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/docs/index.md b/.tessl/tiles/tessl/npm-babel--core/docs/index.md new file mode 100644 index 000000000..e762ea7df --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/docs/index.md @@ -0,0 +1,398 @@ +# Babel Core + +Babel Core is the core compiler for Babel, providing programmatic APIs for JavaScript code transformation, parsing, and configuration. It enables developers to transpile modern JavaScript code into backward-compatible versions, parse JavaScript into Abstract Syntax Trees (ASTs), and configure the transformation process through plugins and presets. + +## Package Information + +- **Package Name**: @babel/core +- **Package Type**: npm +- **Language**: TypeScript +- **Installation**: `npm install @babel/core` + +## Core Imports + +```typescript +import * as babel from "@babel/core"; +``` + +For specific functions: + +```typescript +import { + transform, + transformSync, + parse, + parseSync, + loadOptions, + createConfigItem, + types, + traverse, + template, + type PluginPass, + type Visitor, + type NodePath, + type Scope +} from "@babel/core"; +``` + +CommonJS: + +```javascript +const babel = require("@babel/core"); +const { transform, parse, loadOptions } = require("@babel/core"); +``` + +## Basic Usage + +```typescript +import { transformSync, parseSync } from "@babel/core"; + +// Transform JavaScript code +const result = transformSync(` + const arrow = () => console.log("Hello"); + class MyClass { + method() { return 42; } + } +`, { + presets: ["@babel/preset-env"], + plugins: ["@babel/plugin-transform-arrow-functions"] +}); + +console.log(result.code); +// Output: Transpiled ES5 compatible code + +// Parse JavaScript to AST +const ast = parseSync(` + function hello() { + return "world"; + } +`, { + sourceType: "module", + plugins: ["jsx", "typescript"] +}); + +console.log(ast.type); // "File" +``` + +## Architecture + +Babel Core is built around several key components: + +- **Transformation Engine**: Core APIs (`transform`, `transformSync`, `transformAsync`) that apply plugins and presets to JavaScript code +- **Parser Interface**: Wrapper around @babel/parser (`parse`, `parseSync`, `parseAsync`) for AST generation +- **Configuration System**: Option loading and validation (`loadOptions`, `loadPartialConfig`) with support for config files +- **Plugin/Preset Management**: Configuration item creation and resolution (`createConfigItem`, `resolvePlugin`, `resolvePreset`) +- **File Processing**: File-based transformation APIs (`transformFile`, `transformFileSync`, `transformFileAsync`) +- **AST Processing**: Direct AST transformation (`transformFromAst`, `transformFromAstSync`, `transformFromAstAsync`) + +## Browser Compatibility + +Babel Core includes browser-compatible variants for client-side usage: + +- **File system operations** are replaced with browser-compatible alternatives +- **Config file resolution** is modified for browser environments +- **Transform file APIs** (`transformFile*`) use alternative implementations that don't rely on Node.js file system +- **Module resolution** adapts to browser module loading patterns + +The package automatically uses browser-compatible versions when bundled for web environments through the `browser` field in package.json. + +## Capabilities + +### Code Transformation + +Core JavaScript transformation functionality supporting both code strings and files, with synchronous and asynchronous variants. + +```typescript { .api } +function transformSync( + code: string, + opts?: InputOptions +): FileResult | null; + +function transformAsync( + code: string, + opts?: InputOptions +): Promise; + +function transform(code: string, callback: FileResultCallback): void; +function transform( + code: string, + opts: InputOptions | null | undefined, + callback: FileResultCallback +): void; + +type FileResultCallback = (err: Error | null, result: FileResult | null) => void; + +interface FileResult { + code: string | null; + map: object | null; + ast: object | null; + metadata: object; +} +``` + +[Transformation](./transformation.md) + +### Code Parsing + +JavaScript parsing functionality that converts source code into Abstract Syntax Trees (ASTs) using Babel's parser. + +```typescript { .api } +function parseSync( + code: string, + opts?: InputOptions +): ParseResult | null; + +function parseAsync( + code: string, + opts?: InputOptions +): Promise; + +function parse(code: string, callback: FileParseCallback): void; +function parse( + code: string, + opts: InputOptions | null | undefined, + callback: FileParseCallback +): void; + +type ParseResult = import("@babel/types").File; +type FileParseCallback = (err: Error | null, ast: ParseResult | null) => void; +``` + +[Parsing](./parsing.md) + +### Configuration Management + +Babel configuration loading, validation, and management system supporting various config file formats and runtime options. + +```typescript { .api } +function loadOptionsSync(opts?: InputOptions): ResolvedConfig | null; +function loadOptionsAsync(opts?: InputOptions): Promise; +function loadOptions(opts: InputOptions, callback: (err: Error | null, config: ResolvedConfig | null) => void): void; +function loadOptions(callback: (err: Error | null, config: ResolvedConfig | null) => void): void; + +function loadPartialConfigSync(opts?: InputOptions): PartialConfig | null; +function loadPartialConfigAsync(opts?: InputOptions): Promise; +function loadPartialConfig(opts: InputOptions, callback: (err: Error | null, config: PartialConfig | null) => void): void; +function loadPartialConfig(callback: (err: Error | null, config: PartialConfig | null) => void): void; + +function createConfigItemSync( + target: PluginTarget, + options?: any +): ConfigItem | null; +function createConfigItemAsync( + target: PluginTarget, + options?: any +): Promise | null>; +function createConfigItem( + target: PluginTarget, + options: any, + callback: (err: Error | null, item: ConfigItem | null) => void +): void; +``` + +[Configuration](./configuration.md) + +### Utilities and Constants + +Helper functions, constants, and re-exported APIs from the Babel ecosystem. + +```typescript { .api } +const version: string; +const DEFAULT_EXTENSIONS: readonly string[]; + +function getEnv(defaultValue?: string): string; +function resolvePlugin(name: string, dirname: string): string; +function resolvePreset(name: string, dirname: string): string; +``` + +[Utilities](./utilities.md) + +## Core Types + +```typescript { .api } +interface InputOptions { + /** Input source code filename for error reporting and source maps */ + filename?: string; + /** Input source type: "script", "module", or "unambiguous" */ + sourceType?: "script" | "module" | "unambiguous"; + /** Array of plugins to apply during transformation */ + plugins?: PluginItem[]; + /** Array of presets to apply during transformation */ + presets?: PresetItem[]; + /** Parser options passed to @babel/parser */ + parserOpts?: ParserOptions; + /** Generator options passed to @babel/generator */ + generatorOpts?: GeneratorOptions; + /** Whether to include AST in result */ + ast?: boolean; + /** Source map generation options */ + sourceMaps?: boolean | "inline" | "both"; + /** Code compaction options */ + compact?: boolean | "auto"; + /** Root directory for config file search */ + root?: string; + /** Current working directory */ + cwd?: string; + /** Environment name for conditional config */ + envName?: string; + /** Babel configuration file path or search behavior */ + configFile?: string | false; + /** .babelrc file search behavior */ + babelrc?: boolean; + /** Metadata about the calling tool */ + caller?: CallerMetadata; +} + +interface CallerMetadata { + name: string; + version?: string; + [key: string]: any; +} + +type PluginItem = string | [string, any] | PluginFunction | [PluginFunction, any]; +type PresetItem = string | [string, any] | PresetFunction | [PresetFunction, any]; + +interface FileResult { + /** Transformed JavaScript code */ + code: string | null; + /** Source map for the transformation */ + map: object | null; + /** AST if requested via ast: true option */ + ast: object | null; + /** Metadata from plugins and transformation process */ + metadata: { + [key: string]: any; + }; +} + +interface ResolvedConfig { + /** Resolved and validated options */ + [key: string]: any; +} + +interface PartialConfig { + /** Partial configuration that may need further resolution */ + options: ResolvedConfig | null; + config?: any; + babelrc?: any; + [key: string]: any; +} + +interface ConfigItem { + /** Plugin or preset value */ + value: T; + /** Configuration options */ + options: any; + /** Directory context */ + dirname: string; + /** Item name */ + name?: string; +} + +interface PluginAPI { + /** Plugin target metadata */ + [key: string]: any; +} + +interface PluginPass { + /** Current transformation file context */ + file: File; + /** Plugin key/name */ + key: string; + /** Plugin options */ + opts: any; + /** Current working directory */ + cwd: string; + /** Filename being processed */ + filename?: string; +} + +type Visitor = { + /** Called when entering any AST node */ + enter?(path: NodePath, state: S): void; + /** Called when exiting any AST node */ + exit?(path: NodePath, state: S): void; + /** Specific node type visitors (e.g., FunctionDeclaration, Identifier) */ + [NodeType: string]: + | ((path: NodePath, state: S) => void) + | { enter?(path: NodePath, state: S): void; exit?(path: NodePath, state: S): void } + | undefined; +}; + +interface NodePath { + /** The AST node this path represents */ + node: T; + /** Parent path */ + parent: NodePath | null; + /** Parent AST node */ + parentPath: NodePath | null; + /** Current scope information */ + scope: Scope; + /** Current state passed through traversal */ + state: any; + /** Array of child paths */ + paths?: NodePath[]; + /** Key in parent node */ + key?: string | number; + /** Index if parent is array */ + listKey?: string; + + /** Replace this node with a new node */ + replaceWith(node: any): void; + /** Remove this node */ + remove(): void; + /** Skip traversing children of this node */ + skip(): void; + /** Stop traversal entirely */ + stop(): void; + /** Get the source code for this node */ + getSource(): string; + /** Check if this path represents a specific node type */ + isNodeType(type: string): boolean; + /** Find parent path of specific type */ + findParent(callback: (path: NodePath) => boolean): NodePath | null; + /** Get binding information for identifier */ + get(key: string): NodePath | NodePath[] | null; +} + +interface Scope { + /** Parent scope */ + parent: Scope | null; + /** Path that created this scope */ + path: NodePath; + /** Block that created this scope */ + block: any; + /** All bindings in this scope */ + bindings: { [name: string]: Binding }; + /** Referenced identifiers */ + references: { [name: string]: any[] }; + /** Global scope references */ + globals: { [name: string]: any }; + + /** Check if identifier is bound in this scope */ + hasBinding(name: string): boolean; + /** Get binding for identifier */ + getBinding(name: string): Binding | undefined; + /** Generate unique identifier */ + generateUid(name?: string): string; + /** Add binding to scope */ + registerBinding(kind: string, path: NodePath): void; +} + +interface Binding { + /** Identifier name */ + identifier: any; + /** Scope this binding belongs to */ + scope: Scope; + /** Path that created the binding */ + path: NodePath; + /** Kind of binding (var, let, const, function, etc.) */ + kind: string; + /** Whether binding is referenced */ + referenced: boolean; + /** Number of references */ + references: number; + /** All reference paths */ + referencePaths: NodePath[]; +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/docs/parsing.md b/.tessl/tiles/tessl/npm-babel--core/docs/parsing.md new file mode 100644 index 000000000..b61f8a6f2 --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/docs/parsing.md @@ -0,0 +1,430 @@ +# Code Parsing + +JavaScript parsing functionality that converts source code into Abstract Syntax Trees (ASTs) using Babel's parser. Provides both synchronous and asynchronous parsing with extensive configuration options for different JavaScript dialects and syntax extensions. + +## Capabilities + +### String Parsing + +Parse JavaScript code from strings into Babel ASTs. + +```typescript { .api } +/** + * Parse JavaScript code synchronously + * @param code - JavaScript source code to parse + * @param opts - Parsing options including syntax plugins and parser settings + * @returns Babel AST (File node) or null if parsing fails + */ +function parseSync(code: string, opts?: InputOptions): ParseResult | null; + +/** + * Parse JavaScript code asynchronously + * @param code - JavaScript source code to parse + * @param opts - Parsing options including syntax plugins and parser settings + * @returns Promise resolving to Babel AST (File node) or null + */ +function parseAsync(code: string, opts?: InputOptions): Promise; + +/** + * Parse JavaScript code with callback (legacy API, deprecated in Babel 8) + * @param code - JavaScript source code to parse + * @param opts - Parsing options + * @param callback - Callback function receiving error and AST result + */ +function parse( + code: string, + opts: InputOptions | null | undefined, + callback: FileParseCallback +): void; +function parse(code: string, callback: FileParseCallback): void; + +type ParseResult = import("@babel/types").File; +type FileParseCallback = (err: Error | null, ast: ParseResult | null) => void; +``` + +**Usage Examples:** + +```typescript +import { parseSync, parseAsync } from "@babel/core"; + +// Basic parsing +const ast = parseSync(` + function hello(name) { + return \`Hello \${name}!\`; + } +`, { + sourceType: "module" +}); + +console.log(ast.type); // "File" +console.log(ast.program.type); // "Program" +console.log(ast.program.body[0].type); // "FunctionDeclaration" + +// Parsing with TypeScript syntax +const tsAst = parseSync(` + interface User { + name: string; + age: number; + } + + const user: User = { name: "Alice", age: 30 }; +`, { + sourceType: "module", + plugins: ["typescript"] +}); + +// Parsing with JSX syntax +const jsxAst = parseSync(` + const Component = () => { + return
Hello World
; + }; +`, { + sourceType: "module", + plugins: ["jsx"] +}); + +// Asynchronous parsing +const asyncAst = await parseAsync(` + async function getData() { + const response = await fetch('/api/data'); + return response.json(); + } +`, { + sourceType: "module", + plugins: ["asyncGenerators"] +}); +``` + +### Parser Configuration + +Configure the parsing behavior with various options: + +```typescript { .api } +interface ParseOptions { + /** Source type: "script", "module", or "unambiguous" (default: "script") */ + sourceType?: "script" | "module" | "unambiguous"; + /** Filename for error reporting and source maps */ + filename?: string; + /** Parser-specific options */ + parserOpts?: ParserOptions; + /** Environment name for conditional parsing */ + envName?: string; + /** Current working directory */ + cwd?: string; + /** Root directory for config resolution */ + root?: string; +} + +interface ParserOptions { + /** Syntax plugins to enable */ + plugins?: ParserPlugin[]; + /** Source type override */ + sourceType?: "script" | "module" | "unambiguous"; + /** Allow import/export outside modules */ + allowImportExportEverywhere?: boolean; + /** Allow return statements outside functions */ + allowReturnOutsideFunction?: boolean; + /** Allow undeclared exports */ + allowUndeclaredExports?: boolean; + /** Create parent references on AST nodes */ + createParenthesizedExpressions?: boolean; + /** Track error recovery information */ + errorRecovery?: boolean; + /** Add location information to nodes */ + ranges?: boolean; + /** Include token list in result */ + tokens?: boolean; + /** Strict mode parsing */ + strictMode?: boolean; + /** Start line number (default: 1) */ + startLine?: number; + /** Start column number (default: 0) */ + startColumn?: number; +} + +type ParserPlugin = + | "jsx" + | "typescript" + | "flow" + | "decorators" + | "classProperties" + | "classPrivateProperties" + | "classPrivateMethods" + | "classStaticBlock" + | "asyncGenerators" + | "functionBind" + | "exportDefaultFrom" + | "exportNamespaceFrom" + | "dynamicImport" + | "nullishCoalescingOperator" + | "optionalChaining" + | "importMeta" + | "topLevelAwait" + | "importAssertions" + | "importReflection" + | "bigInt" + | "optionalCatchBinding" + | "throwExpressions" + | "pipelineOperator" + | "recordAndTuple" + | "doExpressions" + | "regexpUnicodeSets" + | ["decorators", { decoratorsBeforeExport?: boolean }] + | ["pipelineOperator", { proposal: "minimal" | "smart" | "fsharp" }] + | ["recordAndTuple", { syntaxType: "bar" | "hash" }] + | ["flow", { all?: boolean; enums?: boolean }] + | ["typescript", { + dts?: boolean; + disallowAmbiguousJSXLike?: boolean; + allowNamespaces?: boolean; + }]; +``` + +**Usage Examples:** + +```typescript +import { parseSync } from "@babel/core"; + +// TypeScript with decorators +const decoratorAst = parseSync(` + @Component({ + selector: 'app-example' + }) + class ExampleComponent { + @Input() value: string; + + @HostListener('click') + onClick() {} + } +`, { + sourceType: "module", + plugins: [ + "typescript", + ["decorators", { decoratorsBeforeExport: true }] + ] +}); + +// Flow type annotations +const flowAst = parseSync(` + type User = { + name: string, + age: number + }; + + function greetUser(user: User): string { + return \`Hello \${user.name}\`; + } +`, { + sourceType: "module", + plugins: [["flow", { all: true }]] +}); + +// Modern JavaScript features +const modernAst = parseSync(` + class APIClient { + #baseUrl = 'https://api.example.com'; + + async getData() { + const response = await fetch(\`\${this.#baseUrl}/data\`); + return response?.json() ?? null; + } + + static { + console.log('APIClient initialized'); + } + } +`, { + sourceType: "module", + plugins: [ + "classPrivateProperties", + "classPrivateMethods", + "classStaticBlock", + "nullishCoalescingOperator", + "optionalChaining", + "topLevelAwait" + ] +}); +``` + +## AST Structure + +The parsing result is a Babel AST with the following structure: + +```typescript { .api } +interface File { + type: "File"; + /** The program node containing all top-level statements */ + program: Program; + /** Comments found in the source code */ + comments: Comment[]; + /** Tokens if tokens: true was specified */ + tokens?: Token[]; + /** Source location information */ + loc?: SourceLocation; + /** Start and end positions */ + start?: number; + end?: number; +} + +interface Program { + type: "Program"; + /** Top-level statements and declarations */ + body: Statement[]; + /** Directive nodes (like "use strict") */ + directives: Directive[]; + /** Source type that was detected/specified */ + sourceType: "script" | "module"; + /** Source location information */ + loc?: SourceLocation; +} + +interface SourceLocation { + /** Starting position */ + start: Position; + /** Ending position */ + end: Position; + /** Original filename */ + filename?: string; + /** Identifier name for anonymous sources */ + identifierName?: string; +} + +interface Position { + /** Line number (1-based) */ + line: number; + /** Column number (0-based) */ + column: number; + /** Character index in source */ + index?: number; +} + +interface Comment { + type: "CommentBlock" | "CommentLine"; + /** Comment text content */ + value: string; + /** Source location */ + loc?: SourceLocation; + /** Start and end positions */ + start?: number; + end?: number; +} +``` + +## Working with ASTs + +Common patterns for working with parsed ASTs: + +```typescript +import { parseSync } from "@babel/core"; +import traverse from "@babel/traverse"; +import * as t from "@babel/types"; + +const code = ` + function add(a, b) { + return a + b; + } + + const multiply = (x, y) => x * y; +`; + +const ast = parseSync(code, { sourceType: "module" }); + +// Traverse the AST +traverse(ast, { + // Visit all function declarations + FunctionDeclaration(path) { + console.log("Function name:", path.node.id.name); + console.log("Parameter count:", path.node.params.length); + }, + + // Visit all arrow functions + ArrowFunctionExpression(path) { + console.log("Arrow function found"); + + // Convert to regular function + const params = path.node.params; + const body = t.isExpression(path.node.body) + ? t.blockStatement([t.returnStatement(path.node.body)]) + : path.node.body; + + path.replaceWith( + t.functionExpression(null, params, body) + ); + } +}); + +// Check node types +traverse(ast, { + enter(path) { + if (t.isIdentifier(path.node)) { + console.log("Identifier:", path.node.name); + } + if (t.isStringLiteral(path.node)) { + console.log("String:", path.node.value); + } + } +}); +``` + +## Error Handling + +Parse functions may throw errors for invalid syntax: + +```typescript +import { parseSync } from "@babel/core"; + +try { + const ast = parseSync("const x = ;", { + sourceType: "module" + }); +} catch (error) { + if (error.code === "BABEL_PARSE_ERROR") { + console.error("Parse error:", error.message); + console.error("Location:", error.loc); // { line: 1, column: 10 } + console.error("Position:", error.pos); // Character position + } +} + +// Handle missing plugins +try { + const tsAst = parseSync("const x: number = 42;", { + sourceType: "module" + // Missing "typescript" plugin + }); +} catch (error) { + console.error("Missing plugin:", error.message); + // "This experimental syntax requires enabling the parser plugin: 'typescript'" +} +``` + +## Integration with Other Babel APIs + +Parsed ASTs can be used with other Babel functions: + +```typescript +import { parseSync, transformFromAstSync, traverse } from "@babel/core"; + +// Parse -> Modify -> Transform workflow +const code = `const greeting = name => \`Hello \${name}\`;`; + +// 1. Parse to AST +const ast = parseSync(code, { + sourceType: "module", + plugins: ["templateLiterals"] +}); + +// 2. Modify AST +traverse(ast, { + TemplateLiteral(path) { + // Convert template literal to concatenation + // This is just an example - in practice use appropriate plugins + } +}); + +// 3. Transform to code +const result = transformFromAstSync(ast, code, { + presets: ["@babel/preset-env"] +}); + +console.log(result.code); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/docs/transformation.md b/.tessl/tiles/tessl/npm-babel--core/docs/transformation.md new file mode 100644 index 000000000..d5c1e3157 --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/docs/transformation.md @@ -0,0 +1,327 @@ +# Code Transformation + +Core JavaScript transformation functionality for converting modern JavaScript code into backward-compatible versions using Babel plugins and presets. Supports string-based, file-based, and AST-based transformation workflows. + +## Capabilities + +### String Transformation + +Transform JavaScript code from strings with full plugin and preset support. + +```typescript { .api } +/** + * Transform JavaScript code synchronously + * @param code - JavaScript source code to transform + * @param opts - Transformation options including plugins, presets, and parser settings + * @returns Transformation result with code, source map, and optional AST + */ +function transformSync(code: string, opts?: InputOptions): FileResult | null; + +/** + * Transform JavaScript code asynchronously + * @param code - JavaScript source code to transform + * @param opts - Transformation options including plugins, presets, and parser settings + * @returns Promise resolving to transformation result + */ +function transformAsync(code: string, opts?: InputOptions): Promise; + +/** + * Transform JavaScript code with callback (legacy API, deprecated in Babel 8) + * @param code - JavaScript source code to transform + * @param opts - Transformation options + * @param callback - Callback function receiving error and result + */ +function transform( + code: string, + opts: InputOptions | null | undefined, + callback: FileResultCallback +): void; +function transform(code: string, callback: FileResultCallback): void; + +type FileResultCallback = (err: Error | null, result: FileResult | null) => void; +``` + +**Usage Examples:** + +```typescript +import { transformSync, transformAsync } from "@babel/core"; + +// Synchronous transformation +const result = transformSync(` + const getMessage = () => "Hello World"; + class User { + constructor(name) { + this.name = name; + } + } +`, { + presets: ["@babel/preset-env"], + plugins: ["@babel/plugin-transform-arrow-functions", "@babel/plugin-transform-classes"] +}); + +console.log(result.code); +// Output: ES5 compatible code + +// Asynchronous transformation +const asyncResult = await transformAsync(` + import { useState } from 'react'; + export const Component = () =>
Hello
; +`, { + presets: ["@babel/preset-react", "@babel/preset-env"], + filename: "component.jsx" +}); + +console.log(asyncResult.code); +``` + +### File Transformation + +Transform JavaScript files directly from the filesystem. + +```typescript { .api } +/** + * Transform JavaScript file synchronously + * @param filename - Path to JavaScript file to transform + * @param opts - Transformation options (filename will be added automatically) + * @returns Transformation result with code, source map, and optional AST + */ +function transformFileSync(filename: string, opts?: InputOptions): FileResult | null; + +/** + * Transform JavaScript file asynchronously + * @param filename - Path to JavaScript file to transform + * @param opts - Transformation options (filename will be added automatically) + * @returns Promise resolving to transformation result + */ +function transformFileAsync(filename: string, opts?: InputOptions): Promise; + +/** + * Transform JavaScript file with callback + * @param filename - Path to JavaScript file to transform + * @param opts - Transformation options + * @param callback - Callback function receiving error and result + */ +function transformFile( + filename: string, + opts: InputOptions | null | undefined, + callback: FileResultCallback +): void; +function transformFile(filename: string, callback: FileResultCallback): void; +``` + +**Usage Examples:** + +```typescript +import { transformFileSync, transformFileAsync } from "@babel/core"; + +// Synchronous file transformation +const result = transformFileSync("./src/app.js", { + presets: ["@babel/preset-env"], + sourceMaps: true +}); + +if (result) { + console.log("Transformed:", result.code); + console.log("Source map:", result.map); +} + +// Asynchronous file transformation +const asyncResult = await transformFileAsync("./src/component.tsx", { + presets: ["@babel/preset-typescript", "@babel/preset-react"], + plugins: ["@babel/plugin-transform-runtime"] +}); +``` + +### AST Transformation + +Transform JavaScript code from existing Abstract Syntax Trees (ASTs). + +```typescript { .api } +/** + * Transform from AST synchronously + * @param ast - Babel AST (File or Program node) + * @param code - Original source code string for source map generation + * @param opts - Transformation options + * @returns Transformation result with code, source map, and optional AST + */ +function transformFromAstSync( + ast: AstRoot, + code: string, + opts?: InputOptions +): FileResult | null; + +/** + * Transform from AST asynchronously + * @param ast - Babel AST (File or Program node) + * @param code - Original source code string for source map generation + * @param opts - Transformation options + * @returns Promise resolving to transformation result + */ +function transformFromAstAsync( + ast: AstRoot, + code: string, + opts?: InputOptions +): Promise; + +/** + * Transform from AST with callback (legacy API, deprecated in Babel 8) + * @param ast - Babel AST (File or Program node) + * @param code - Original source code string + * @param opts - Transformation options + * @param callback - Callback function receiving error and result + */ +function transformFromAst( + ast: AstRoot, + code: string, + opts: InputOptions | null | undefined, + callback: FileResultCallback +): void; +function transformFromAst( + ast: AstRoot, + code: string, + callback: FileResultCallback +): void; + +type AstRoot = import("@babel/types").File | import("@babel/types").Program; +``` + +**Usage Examples:** + +```typescript +import { parseSync, transformFromAstSync } from "@babel/core"; + +// Parse then transform +const code = `const x = () => 42;`; +const ast = parseSync(code, { + sourceType: "module", + plugins: ["jsx"] +}); + +const result = transformFromAstSync(ast, code, { + presets: ["@babel/preset-env"] +}); + +console.log(result.code); +// Output: Transformed code from the AST + +// Modify AST before transformation +import traverse from "@babel/traverse"; +import * as t from "@babel/types"; + +traverse(ast, { + ArrowFunctionExpression(path) { + // Convert arrow function to regular function + path.replaceWith( + t.functionExpression(null, path.node.params, + t.blockStatement([t.returnStatement(path.node.body)]) + ) + ); + } +}); + +const modifiedResult = transformFromAstSync(ast, code, { + presets: ["@babel/preset-env"] +}); +``` + +## Transformation Result + +All transformation functions return a `FileResult` object containing the transformed code and metadata. + +```typescript { .api } +interface FileResult { + /** Transformed JavaScript code, null if transformation was skipped */ + code: string | null; + /** Source map object for debugging, null if source maps disabled */ + map: object | null; + /** AST object if ast: true option was provided, null otherwise */ + ast: object | null; + /** Metadata collected during transformation including plugin information */ + metadata: { + /** Modules that were processed during transformation */ + modules?: { + imports: Array<{ + source: string; + imported: string[]; + specifiers: any[]; + }>; + exports: Array<{ + exported: string[]; + specifiers: any[]; + }>; + }; + /** List of external helper functions that were used */ + externalHelpers?: string[]; + /** Plugin-specific metadata */ + [pluginName: string]: any; + }; +} +``` + +## Common Transformation Options + +Key options for controlling the transformation process: + +```typescript { .api } +interface TransformationOptions { + /** Plugins to apply during transformation */ + plugins?: Array; + /** Presets to apply during transformation (applied before plugins) */ + presets?: Array; + /** Include AST in result (default: false) */ + ast?: boolean; + /** Generate source maps: false, true, "inline", or "both" */ + sourceMaps?: boolean | "inline" | "both"; + /** Compact output: true, false, or "auto" (default: "auto") */ + compact?: boolean | "auto"; + /** Environment name for conditional configuration */ + envName?: string; + /** Override source filename in source maps and error messages */ + filename?: string; + /** Parser options passed to @babel/parser */ + parserOpts?: { + sourceType?: "script" | "module" | "unambiguous"; + allowImportExportEverywhere?: boolean; + allowReturnOutsideFunction?: boolean; + plugins?: string[]; + strictMode?: boolean; + ranges?: boolean; + tokens?: boolean; + }; + /** Generator options passed to @babel/generator */ + generatorOpts?: { + /** Retain parentheses around expressions */ + retainLines?: boolean; + /** Compact whitespace */ + compact?: boolean; + /** Number of spaces for indentation */ + indent?: number; + /** Quote style: "single" or "double" */ + quotes?: "single" | "double"; + }; +} +``` + +## Error Handling + +Transformation functions may throw errors for various reasons: + +```typescript +import { transformSync } from "@babel/core"; + +try { + const result = transformSync("invalid syntax {{", { + presets: ["@babel/preset-env"] + }); +} catch (error) { + if (error.code === "BABEL_PARSE_ERROR") { + console.error("Parse error:", error.message); + console.error("Location:", error.loc); + } else if (error.code === "BABEL_TRANSFORM_ERROR") { + console.error("Transform error:", error.message); + console.error("Plugin:", error.plugin); + } else { + console.error("Other error:", error.message); + } +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/docs/utilities.md b/.tessl/tiles/tessl/npm-babel--core/docs/utilities.md new file mode 100644 index 000000000..a5b936dd3 --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/docs/utilities.md @@ -0,0 +1,564 @@ +# Utilities and Constants + +Helper functions, constants, and re-exported APIs from the Babel ecosystem. Includes version information, file extensions, environment detection, plugin resolution, and access to the complete Babel toolchain. + +## Capabilities + +### Version and Constants + +Version information and recommended file extensions for Babel processing. + +```typescript { .api } +/** + * Current version of @babel/core package + */ +const version: string; + +/** + * Recommended set of compilable file extensions + * Not used in @babel/core directly, but meant as an easy source for tooling + */ +const DEFAULT_EXTENSIONS: readonly [".js", ".jsx", ".es6", ".es", ".mjs", ".cjs"]; +``` + +**Usage Examples:** + +```typescript +import { version, DEFAULT_EXTENSIONS } from "@babel/core"; + +console.log("Babel version:", version); // "7.26.10" + +console.log("Default extensions:", DEFAULT_EXTENSIONS); +// [".js", ".jsx", ".es6", ".es", ".mjs", ".cjs"] + +// Use in build tools +const shouldProcess = (filename) => { + return DEFAULT_EXTENSIONS.some(ext => filename.endsWith(ext)); +}; + +console.log(shouldProcess("app.js")); // true +console.log(shouldProcess("styles.css")); // false +``` + +### Environment Detection + +Detect and resolve the current Babel environment. + +```typescript { .api } +/** + * Get the current Babel environment name + * @param defaultValue - Default environment if none specified (default: "development") + * @returns Environment name from BABEL_ENV, NODE_ENV, or default value + */ +function getEnv(defaultValue?: string): string; +``` + +**Usage Examples:** + +```typescript +import { getEnv } from "@babel/core"; + +// Without environment variables set +console.log(getEnv()); // "development" +console.log(getEnv("production")); // "production" + +// With NODE_ENV=test +process.env.NODE_ENV = "test"; +console.log(getEnv()); // "test" + +// With BABEL_ENV=staging (takes precedence over NODE_ENV) +process.env.BABEL_ENV = "staging"; +console.log(getEnv()); // "staging" + +// Use in configuration +const isProd = getEnv() === "production"; +const isDev = getEnv() === "development"; +``` + +### Plugin and Preset Resolution + +Resolve plugin and preset file paths (legacy APIs for backward compatibility). + +```typescript { .api } +/** + * Resolve plugin file path (legacy API) + * @param name - Plugin name or path + * @param dirname - Directory to resolve from + * @returns Resolved file path + */ +function resolvePlugin(name: string, dirname: string): string; + +/** + * Resolve preset file path (legacy API) + * @param name - Preset name or path + * @param dirname - Directory to resolve from + * @returns Resolved file path + */ +function resolvePreset(name: string, dirname: string): string; +``` + +**Usage Examples:** + +```typescript +import { resolvePlugin, resolvePreset } from "@babel/core"; + +// Resolve official plugins +const pluginPath = resolvePlugin("@babel/plugin-transform-arrow-functions", __dirname); +console.log(pluginPath); // "/path/to/node_modules/@babel/plugin-transform-arrow-functions/lib/index.js" + +// Resolve official presets +const presetPath = resolvePreset("@babel/preset-env", process.cwd()); +console.log(presetPath); // "/path/to/node_modules/@babel/preset-env/lib/index.js" + +// Resolve relative paths +const localPlugin = resolvePlugin("./plugins/custom-plugin", __dirname); +console.log(localPlugin); // "/current/dir/plugins/custom-plugin.js" + +// Use in plugin loading +function loadPlugin(name, dirname) { + try { + const pluginPath = resolvePlugin(name, dirname); + return require(pluginPath); + } catch (error) { + console.error(`Failed to load plugin ${name}:`, error.message); + } +} +``` + +### External Helper Generation + +Generate external Babel helper functions for runtime optimization. + +```typescript { .api } +/** + * Build external helper functions as a single module + * @param whitelist - Array of helper names to include, or undefined for all + * @param outputType - Output format: "global", "umd", "var", or function + * @returns Generated helper code as string + */ +function buildExternalHelpers( + whitelist?: string[], + outputType?: "global" | "umd" | "var" | ((name: string) => string) +): string; +``` + +**Usage Examples:** + +```typescript +import { buildExternalHelpers } from "@babel/core"; + +// Generate all helpers as global variables +const allHelpers = buildExternalHelpers(undefined, "global"); +console.log(allHelpers); +// Output: Global helper functions for all Babel runtime helpers + +// Generate specific helpers only +const specificHelpers = buildExternalHelpers([ + "_classCallCheck", + "_createClass", + "_inherits" +], "umd"); +console.log(specificHelpers); +// Output: UMD module with class-related helpers only + +// Generate with custom output format +const customHelpers = buildExternalHelpers( + ["_asyncToGenerator", "_awaitAsyncGenerator"], + (name) => `window.BabelHelpers.${name.slice(1)}` +); +console.log(customHelpers); +// Output: Helpers assigned to window.BabelHelpers + +// Use in build process +const fs = require("fs"); +const helpers = buildExternalHelpers(undefined, "umd"); +fs.writeFileSync("dist/babel-helpers.js", helpers); +``` + +## Re-exported APIs + +Babel Core re-exports several essential APIs from other Babel packages for convenience. + +### Babel Types + +Complete AST node types and utilities from @babel/types. + +```typescript { .api } +/** + * Complete @babel/types API for AST manipulation + * Includes all node builders, validators, and utilities + */ +import * as types from "@babel/types"; + +// Re-exported as namespace +export * as types from "@babel/types"; +``` + +**Usage Examples:** + +```typescript +import { types as t } from "@babel/core"; +// or: import * as t from "@babel/core"; + +// Create AST nodes +const identifier = t.identifier("myVariable"); +const stringLiteral = t.stringLiteral("Hello World"); +const callExpression = t.callExpression( + t.identifier("console.log"), + [stringLiteral] +); + +// Validate node types +if (t.isIdentifier(identifier)) { + console.log("Name:", identifier.name); +} + +if (t.isCallExpression(callExpression)) { + console.log("Callee:", callExpression.callee); + console.log("Arguments:", callExpression.arguments); +} + +// Build complex structures +const functionDeclaration = t.functionDeclaration( + t.identifier("greet"), + [t.identifier("name")], + t.blockStatement([ + t.returnStatement( + t.templateLiteral( + [ + t.templateElement({ raw: "Hello " }, false), + t.templateElement({ raw: "!" }, true) + ], + [t.identifier("name")] + ) + ) + ]) +); +``` + +### Babel Traverse + +AST traversal utilities from @babel/traverse. + +```typescript { .api } +/** + * Default traverse function for AST traversal + */ +export { default as traverse } from "@babel/traverse"; + +/** + * Node path type for AST traversal + */ +export type { NodePath } from "@babel/traverse"; + +/** + * Scope information type + */ +export type { Scope } from "@babel/traverse"; + +/** + * Visitor pattern type for AST traversal + */ +export type Visitor = import("@babel/traverse").Visitor; +``` + +**Usage Examples:** + +```typescript +import { traverse, parseSync, types as t } from "@babel/core"; + +const code = ` + function calculate(a, b) { + const result = a + b; + return result; + } +`; + +const ast = parseSync(code, { sourceType: "module" }); + +// Basic traversal +traverse(ast, { + enter(path) { + console.log("Entering:", path.node.type); + }, + + exit(path) { + console.log("Exiting:", path.node.type); + } +}); + +// Specific node visitors +traverse(ast, { + FunctionDeclaration(path) { + console.log("Function:", path.node.id.name); + console.log("Parameters:", path.node.params.map(p => p.name)); + }, + + VariableDeclarator(path) { + if (t.isIdentifier(path.node.id)) { + console.log("Variable:", path.node.id.name); + } + }, + + BinaryExpression(path) { + console.log("Operation:", path.node.operator); + console.log("Left:", path.node.left); + console.log("Right:", path.node.right); + } +}); + +// Path manipulation +traverse(ast, { + Identifier(path) { + if (path.node.name === "result") { + path.node.name = "output"; + } + } +}); +``` + +### Babel Template + +Template string to AST conversion from @babel/template. + +```typescript { .api } +/** + * Template function for converting template strings to AST nodes + */ +export { default as template } from "@babel/template"; +``` + +**Usage Examples:** + +```typescript +import { template, traverse, parseSync } from "@babel/core"; + +// Create template functions +const buildRequire = template(` + var %%importName%% = require(%%source%%); +`); + +const buildClass = template.statement(` + class %%className%% extends %%superClass%% { + constructor(%%params%%) { + super(%%args%%); + %%body%% + } + } +`); + +// Use templates to generate AST +const requireNode = buildRequire({ + importName: t.identifier("lodash"), + source: t.stringLiteral("lodash") +}); + +const classNode = buildClass({ + className: t.identifier("MyComponent"), + superClass: t.identifier("Component"), + params: [t.identifier("props")], + args: [t.identifier("props")], + body: [ + t.expressionStatement( + t.assignmentExpression( + "=", + t.memberExpression(t.thisExpression(), t.identifier("state")), + t.objectExpression([]) + ) + ) + ] +}); + +// Template with expressions +const buildConditional = template.expression(` + %%test%% ? %%consequent%% : %%alternate%% +`); + +const conditional = buildConditional({ + test: t.identifier("isLoggedIn"), + consequent: t.stringLiteral("Welcome"), + alternate: t.stringLiteral("Please log in") +}); +``` + +### Babel Parser Token Types + +Token types from @babel/parser for advanced parsing use cases. + +```typescript { .api } +/** + * Token types from Babel parser + */ +export { tokTypes } from "@babel/parser"; +``` + +**Usage Examples:** + +```typescript +import { tokTypes, parseSync } from "@babel/core"; + +// Parse with tokens +const ast = parseSync("const x = 42;", { + sourceType: "module", + tokens: true +}); + +// Check token types +if (ast.tokens) { + ast.tokens.forEach(token => { + if (token.type === tokTypes.name) { + console.log("Identifier token:", token.value); + } else if (token.type === tokTypes.num) { + console.log("Number token:", token.value); + } else if (token.type === tokTypes._const) { + console.log("Const keyword token"); + } + }); +} + +// Token type checking +console.log("Available token types:", Object.keys(tokTypes)); +// ["num", "string", "name", "_const", "_let", "_var", ...] +``` + +## File Context Class + +The File class provides transformation context and utilities, primarily used in plugin development and advanced transformation scenarios. + +```typescript { .api } +/** + * File transformation context class + * Provides access to transformation state, metadata, and helper functions + */ +export { default as File } from "./transformation/file/file"; + +class File { + /** Transformation options merged from config and parameters */ + opts: TransformationOptions; + /** Variable declarations at file scope */ + declarations: { [name: string]: import("@babel/types").Identifier }; + /** Root program path for AST traversal */ + path: import("@babel/traverse").NodePath; + /** Complete file AST including program and metadata */ + ast: import("@babel/types").File; + /** Root scope for the file */ + scope: import("@babel/traverse").Scope; + /** Metadata collected from plugins during transformation */ + metadata: { [pluginName: string]: any }; + /** Original source code string */ + code: string; + /** Input source map if available */ + inputMap: import("convert-source-map").SourceMapConverter | null; + + /** Hub interface for plugin communication and utilities */ + hub: FileHub; + + /** Generate a unique identifier in file scope */ + generateUid(name: string): import("@babel/types").Identifier; + /** Check if identifier is available in file scope */ + hasIdentifier(name: string): boolean; + /** Add import declaration to file */ + addImport(source: string, importedName: string, localName?: string): import("@babel/types").Identifier; + /** Add helper function import */ + addHelper(name: string): import("@babel/types").Identifier; +} + +interface FileHub { + /** Reference to the current file */ + file: File; + /** Get current transformed code */ + getCode(): string; + /** Get file root scope */ + getScope(): import("@babel/traverse").Scope; + /** Add Babel helper function and return its identifier */ + addHelper(name: string): import("@babel/types").Identifier; + /** Create error with location information */ + buildError( + node: T, + message: string, + constructor?: typeof Error + ): Error; +} + +interface TransformationOptions { + /** Source filename */ + filename?: string; + /** Source type */ + sourceType?: "script" | "module" | "unambiguous"; + /** Plugins to apply */ + plugins?: any[]; + /** Presets to apply */ + presets?: any[]; + /** Parser options */ + parserOpts?: any; + /** Generator options */ + generatorOpts?: any; + /** Additional transformation options */ + [key: string]: any; +} +``` + +**Usage in Plugin Development:** + +```typescript +import { PluginObj, PluginPass } from "@babel/core"; +import * as t from "@babel/types"; + +function myPlugin(): PluginObj { + return { + visitor: { + Program(path, state: PluginPass) { + // Access file context + const file = state.file; + + // Get transformation options + console.log("Filename:", file.opts.filename); + console.log("Source type:", file.opts.sourceType); + + // Add helper function + const helperIdentifier = file.addHelper("classCallCheck"); + + // Generate unique identifier + const uniqueId = file.generateUid("temp"); + + // Add metadata for other plugins + file.metadata.myPlugin = { + processedNodes: 0, + addedHelpers: [helperIdentifier.name] + }; + + // Access file scope + const hasConsole = file.scope.hasBinding("console"); + console.log("Console available:", hasConsole); + }, + + ClassDeclaration(path, state: PluginPass) { + const file = state.file; + + // Increment counter in metadata + if (!file.metadata.myPlugin) { + file.metadata.myPlugin = { processedNodes: 0 }; + } + file.metadata.myPlugin.processedNodes++; + + // Create error with file context + if (path.node.id === null) { + throw file.hub.buildError( + path.node, + "Anonymous classes are not supported" + ); + } + } + } + }; +} +``` + +The File class is essential for plugin authors who need to: + +1. **Access transformation context** - filename, options, and configuration +2. **Manage helper functions** - automatically import required runtime helpers +3. **Generate unique identifiers** - avoid naming conflicts in transformed code +4. **Share data between plugins** - using the metadata system +5. **Handle errors with context** - provide meaningful error messages with location info +6. **Access file-level scope information** - understand available bindings and references \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--core/tile.json b/.tessl/tiles/tessl/npm-babel--core/tile.json new file mode 100644 index 000000000..da231e49d --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--core/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/npm-babel--core", + "version": "7.26.0", + "docs": "docs/index.md", + "describes": "pkg:npm/@babel/core@7.26.10", + "summary": "Babel compiler core providing programmatic APIs for JavaScript code transformation, parsing, and configuration." +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md b/.tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md new file mode 100644 index 000000000..56754b682 --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md @@ -0,0 +1,376 @@ +# @babel/preset-typescript + +@babel/preset-typescript is a Babel preset that enables TypeScript compilation through Babel's plugin pipeline. It configures the necessary plugins to transform TypeScript syntax into JavaScript while maintaining compatibility with Babel's ecosystem and build tools. + +## Package Information + +- **Package Name**: @babel/preset-typescript +- **Package Type**: npm +- **Language**: TypeScript/JavaScript +- **Installation**: `npm install --save-dev @babel/preset-typescript` + +## Core Imports + +```javascript +// babel.config.js +module.exports = { + presets: ['@babel/preset-typescript'] +}; +``` + +With options: + +```javascript +// babel.config.js +module.exports = { + presets: [ + ['@babel/preset-typescript', { + allowNamespaces: true, + onlyRemoveTypeImports: true, + optimizeConstEnums: false + }] + ] +}; +``` + +For programmatic usage: + +```javascript +const presetTypescript = require('@babel/preset-typescript').default; +// or +import presetTypescript from '@babel/preset-typescript'; +``` + +## Basic Usage + +```javascript +// babel.config.js - Basic configuration +module.exports = { + presets: ['@babel/preset-typescript'] +}; +``` + +```javascript +// babel.config.js - Advanced configuration +module.exports = { + presets: [ + ['@babel/preset-typescript', { + // Allow TypeScript namespaces (default: true) + allowNamespaces: true, + + // Only remove type-only imports (default: true in Babel 8) + onlyRemoveTypeImports: true, + + // Optimize const enum transformations (default: false) + optimizeConstEnums: false, + + // Custom JSX pragma (default: "React") + jsxPragma: "React", + + // Custom JSX fragment pragma (default: "React.Fragment") + jsxPragmaFrag: "React.Fragment", + + // Rewrite TypeScript import extensions (default: false) + rewriteImportExtensions: false + }] + ] +}; +``` + +## Architecture + +The preset is built around several key components: + +- **Core Preset Function**: Main function that configures TypeScript transformation plugins based on options and file extensions +- **Options Normalizer**: Validates and normalizes configuration options with Babel version-specific behavior +- **Import Rewriter Plugin**: Optional plugin that rewrites TypeScript import extensions to JavaScript equivalents +- **Plugin Configuration**: Automatically configures `@babel/plugin-transform-typescript`, JSX syntax support, and CommonJS transformation based on file types + +## Capabilities + +### Preset Configuration + +The main preset function that configures TypeScript transformation for Babel. The preset is exported as the default export wrapped in Babel's `declarePreset` utility. + +```typescript { .api } +// The actual export from @babel/preset-typescript +const preset: (api: PresetAPI, options?: Options, dirname?: string) => PresetObject; + +// From @babel/core +interface PresetObject { + plugins?: PluginList; + presets?: PresetList; + overrides?: Array; + env?: { [envName: string]: PresetObject }; + ignore?: IgnoreList; + only?: IgnoreList; + test?: ConfigApplicableTest; + include?: ConfigApplicableTest; + exclude?: ConfigApplicableTest; +} + +// The preset returns a configuration with plugins and overrides +interface PresetResult { + plugins: Array; + overrides: Array<{ + test?: RegExp | ((filename?: string) => boolean); + sourceType?: "module" | "unambiguous"; + plugins: Array; + }>; +} +``` + +### Options Configuration + +Configuration options for customizing TypeScript transformation behavior. + +```typescript { .api } +interface Options { + /** Ignore file extensions when determining file type */ + ignoreExtensions?: boolean; + + /** Allow TypeScript declare fields (Babel 7 only) */ + allowDeclareFields?: boolean; + + /** Allow TypeScript namespaces (default: true) */ + allowNamespaces?: boolean; + + /** Disallow ambiguous JSX-like syntax */ + disallowAmbiguousJSXLike?: boolean; + + /** JSX pragma to use (default: "React") */ + jsxPragma?: string; + + /** JSX fragment pragma (default: "React.Fragment") */ + jsxPragmaFrag?: string; + + /** Only remove type-only imports */ + onlyRemoveTypeImports?: boolean; + + /** Optimize const enums transformation */ + optimizeConstEnums?: boolean; + + /** Rewrite TypeScript import extensions to JavaScript */ + rewriteImportExtensions?: boolean; + + /** Handle all file extensions (deprecated in Babel 8) */ + allExtensions?: boolean; + + /** Force JSX parsing (deprecated in Babel 8) */ + isTSX?: boolean; +} +``` + +### Option Normalization + +**Internal function** that validates and normalizes preset options. This function is not exported from the main package and is only used internally by the preset. + +```typescript { .api } +// Internal function - NOT exported from @babel/preset-typescript +// Located in: src/normalize-options.ts +function normalizeOptions(options?: Options): Required; +``` + +**Usage:** Called internally by the preset to validate and apply default values to user-provided options. This function handles Babel version-specific option validation and provides helpful error messages for deprecated options. + +### Import Extension Rewriting + +**Internal plugin** that rewrites TypeScript import extensions to JavaScript equivalents. This plugin is not exported from the main package and is only used internally when `rewriteImportExtensions: true` is specified. + +```typescript { .api } +// Internal plugin - NOT exported from @babel/preset-typescript +// Located in: src/plugin-rewrite-ts-imports.ts +function pluginRewriteTSImports(): PluginObject; + +// From @babel/core +interface PluginObject { + name?: string; + visitor: Visitor; + pre?: (state: any) => void; + post?: (state: any) => void; + manipulateOptions?: (opts: any, parserOpts: any) => void; +} +``` + +**Transformation Examples:** +- `./module.ts` → `./module.js` +- `./component.tsx` → `./component.jsx` (or `.js` if JSX preservation is disabled) +- `./module.mts` → `./module.mjs` +- `./module.cts` → `./module.cjs` +- `./types.d.ts` → `./types.d.ts` (preserved) + +## File Extension Handling + +The preset automatically applies different plugin configurations based on file extensions: + +### TypeScript Files (.ts) + +Standard TypeScript files receive basic TypeScript transformation: + +```javascript +// Configuration applied for .ts files +{ + plugins: [ + ['@babel/plugin-transform-typescript', { + allowNamespaces: true, + disallowAmbiguousJSXLike: false, + // ... other options + }] + ] +} +``` + +### TypeScript JSX Files (.tsx) + +TypeScript files with JSX receive TypeScript transformation plus JSX syntax support: + +```javascript +// Configuration applied for .tsx files +{ + plugins: [ + ['@babel/plugin-transform-typescript', { + isTSX: true, + allowNamespaces: true, + // ... other options + }], + '@babel/plugin-syntax-jsx' + ] +} +``` + +### ES Module TypeScript (.mts) + +TypeScript ES module files with strict module type checking: + +```javascript +// Configuration applied for .mts files +{ + sourceType: "module", + plugins: [ + ['@babel/plugin-transform-typescript', { + disallowAmbiguousJSXLike: true, + // ... other options + }] + ] +} +``` + +### CommonJS TypeScript (.cts) + +TypeScript CommonJS files with automatic CommonJS transformation: + +```javascript +// Configuration applied for .cts files +{ + sourceType: "unambiguous", + plugins: [ + ['@babel/plugin-transform-modules-commonjs', { + allowTopLevelThis: true + }], + ['@babel/plugin-transform-typescript', { + disallowAmbiguousJSXLike: true, + // ... other options + }] + ] +} +``` + +## Version Compatibility + +### Babel 7 Compatibility + +Babel 7 supports additional legacy options: + +- `allowDeclareFields`: Controls TypeScript declare field support +- `allExtensions`: Forces handling of all file extensions +- `isTSX`: Forces JSX parsing for all files + +### Babel 8 Compatibility + +Babel 8 removes deprecated options and enforces stricter validation: + +- Removes `allowDeclareFields`, `allExtensions`, and `isTSX` options +- Stricter option validation with helpful error messages +- Enhanced Node.js version requirements (>=20.19.0 || >=22.12.0) + +## Plugin Dependencies + +The preset automatically configures these Babel plugins: + +- **@babel/plugin-transform-typescript**: Core TypeScript syntax transformation +- **@babel/plugin-syntax-jsx**: JSX syntax parsing support +- **@babel/plugin-transform-modules-commonjs**: CommonJS module transformation (for .cts files) + +## Common Configuration Examples + +### React TypeScript Project + +```javascript +// babel.config.js +module.exports = { + presets: [ + ['@babel/preset-typescript', { + jsxPragma: 'React', + jsxPragmaFrag: 'React.Fragment' + }], + '@babel/preset-react' + ] +}; +``` + +### Node.js TypeScript Project + +```javascript +// babel.config.js +module.exports = { + presets: [ + ['@babel/preset-typescript', { + allowNamespaces: true, + optimizeConstEnums: true + }], + ['@babel/preset-env', { + targets: { node: 'current' } + }] + ] +}; +``` + +### Strict TypeScript Configuration + +```javascript +// babel.config.js +module.exports = { + presets: [ + ['@babel/preset-typescript', { + onlyRemoveTypeImports: true, + disallowAmbiguousJSXLike: true, + ignoreExtensions: true + }] + ] +}; +``` + +### Import Extension Rewriting + +```javascript +// babel.config.js +module.exports = { + presets: [ + ['@babel/preset-typescript', { + rewriteImportExtensions: true + }] + ] +}; +``` + +This configuration transforms: + +```typescript +// Input TypeScript +import { helper } from './utils.ts'; +import Component from './Component.tsx'; + +// Output JavaScript +import { helper } from './utils.js'; +import Component from './Component.jsx'; +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-babel--preset-typescript/tile.json b/.tessl/tiles/tessl/npm-babel--preset-typescript/tile.json new file mode 100644 index 000000000..c8b2aafed --- /dev/null +++ b/.tessl/tiles/tessl/npm-babel--preset-typescript/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/npm-babel--preset-typescript", + "version": "7.27.0", + "docs": "docs/index.md", + "describes": "pkg:npm/@babel/preset-typescript@7.27.1", + "summary": "Babel preset for TypeScript compilation through Babel's plugin pipeline" +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-management.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-management.md new file mode 100644 index 000000000..5e0d3de53 --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-management.md @@ -0,0 +1,253 @@ +# Database Management + +Core database connection and lifecycle management functionality for creating, configuring, and controlling SQLite database connections. + +## Capabilities + +### Database Constructor + +Creates a new database connection with comprehensive configuration options. + +```javascript { .api } +/** + * Creates a new database connection + * @param {string|Buffer} filename - Database file path, ":memory:" for in-memory, or Buffer for serialized database + * @param {Object} [options] - Database configuration options + * @returns {Database} Database instance + */ +function Database(filename, options); + +interface DatabaseOptions { + readonly?: boolean; // Open in readonly mode (default: false) + fileMustExist?: boolean; // Throw error if file doesn't exist (default: false) + timeout?: number; // Timeout in ms for locked database (default: 5000) + verbose?: Function; // Function called with every SQL execution + nativeBinding?: string | Object; // Path to native binding or binding object +} +``` + +**Usage Examples:** + +```javascript +const Database = require('better-sqlite3'); + +// Create/open a file database +const db = new Database('myapp.db'); + +// Create in-memory database +const memDb = new Database(':memory:'); + +// Create temporary database (deleted when closed) +const tempDb = new Database(''); + +// Open readonly database +const readOnlyDb = new Database('data.db', { readonly: true }); + +// Database with timeout and verbose logging +const verboseDb = new Database('app.db', { + timeout: 10000, + verbose: console.log +}); + +// Database that must exist (throws if file missing) +const existingDb = new Database('existing.db', { fileMustExist: true }); + +// Create from serialized buffer +const serializedBuffer = fs.readFileSync('backup.db'); +const restoredDb = new Database(serializedBuffer); +``` + +### Direct SQL Execution + +Execute SQL statements directly without prepared statements. + +```javascript { .api } +/** + * Execute SQL string directly (no prepared statement) + * @param {string} sql - SQL query string (can contain multiple statements) + * @returns {Database} Database instance for chaining + */ +exec(sql); +``` + +**Usage Examples:** + +```javascript +// Create tables and initial data +db.exec(` + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + email TEXT UNIQUE + ); + + CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); + + INSERT OR IGNORE INTO users (name, email) VALUES + ('Admin', 'admin@example.com'), + ('Guest', 'guest@example.com'); +`); + +// Drop and recreate table +db.exec('DROP TABLE IF EXISTS temp_data; CREATE TABLE temp_data (value TEXT);'); +``` + +### Database Connection Management + +Close database connections and manage connection lifecycle. + +```javascript { .api } +/** + * Close database connection + * @returns {Database} Database instance for chaining + */ +close(); +``` + +**Usage Examples:** + +```javascript +// Proper database cleanup +try { + const db = new Database('myapp.db'); + + // Use database... + +} finally { + // Always close the database + db.close(); +} + +// Check if database is still open +console.log(db.open); // false after closing +``` + +### Extension Loading + +Load SQLite extensions to add functionality. + +```javascript { .api } +/** + * Load SQLite extension + * @param {string} path - Path to extension file (.dll, .so, .dylib) + * @param {string} [entrypoint] - Entry point function name (optional) + * @returns {Database} Database instance for chaining + */ +loadExtension(path, entrypoint); +``` + +**Usage Examples:** + +```javascript +// Load extension with automatic entry point +db.loadExtension('./extensions/json1.so'); + +// Load extension with specific entry point +db.loadExtension('./extensions/fts5.so', 'sqlite3_fts5_init'); + +// Load multiple extensions +db.loadExtension('./extensions/rtree.so') + .loadExtension('./extensions/soundex.so'); +``` + +### Database Configuration + +Configure database-wide settings for integer handling and safety modes. + +```javascript { .api } +/** + * Set default safe integer handling for new statements + * @param {boolean} enabled - Enable safe integers by default + * @returns {Database} Database instance for chaining + */ +defaultSafeIntegers(enabled); + +/** + * Enable/disable unsafe mode (disables certain safety checks) + * @param {boolean} enabled - Enable unsafe mode + * @returns {Database} Database instance for chaining + */ +unsafeMode(enabled); +``` + +**Usage Examples:** + +```javascript +// Enable safe integers for large numbers +db.defaultSafeIntegers(true); + +// All new prepared statements will use safe integers +const stmt = db.prepare('SELECT very_large_number FROM table'); +const result = stmt.get(); // Returns BigInt for large integers + +// Enable unsafe mode for maximum performance (use with caution) +db.unsafeMode(true); +``` + +### Database Properties + +Read-only properties providing database connection information. + +```javascript { .api } +interface DatabaseProperties { + readonly name: string; // Database filename or ":memory:" + readonly open: boolean; // Whether connection is open + readonly inTransaction: boolean; // Whether currently in transaction + readonly readonly: boolean; // Whether database is readonly + readonly memory: boolean; // Whether database is in-memory +} +``` + +**Usage Examples:** + +```javascript +const db = new Database('myapp.db', { readonly: true }); + +console.log(db.name); // "myapp.db" +console.log(db.open); // true +console.log(db.readonly); // true +console.log(db.memory); // false +console.log(db.inTransaction); // false + +// Properties update automatically +const transaction = db.transaction(() => { + console.log(db.inTransaction); // true during transaction +}); + +transaction(); +console.log(db.inTransaction); // false after transaction + +db.close(); +console.log(db.open); // false +``` + +## Error Handling + +```javascript { .api } +class SqliteError extends Error { + constructor(message, code); + readonly name: string; // Always "SqliteError" + readonly code: string; // SQLite error code (e.g., "SQLITE_CONSTRAINT") + readonly message: string; // Descriptive error message +} +``` + +**Common Error Scenarios:** + +```javascript +try { + const db = new Database('nonexistent.db', { fileMustExist: true }); +} catch (error) { + if (error instanceof Database.SqliteError) { + console.log(error.code); // "SQLITE_CANTOPEN" + console.log(error.message); // "Cannot open database..." + } +} + +try { + db.exec('INVALID SQL SYNTAX'); +} catch (error) { + console.log(error.code); // "SQLITE_ERROR" + console.log(error.message); // "near \"INVALID\": syntax error" +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md new file mode 100644 index 000000000..1a402884f --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md @@ -0,0 +1,362 @@ +# Database Utilities + +Utility functions for database introspection, backup, serialization, and configuration management. + +## Capabilities + +### PRAGMA Commands + +Execute PRAGMA commands for database configuration and introspection. + +```javascript { .api } +/** + * Execute PRAGMA commands for database configuration and introspection + * @param {string} source - PRAGMA command string (without "PRAGMA" prefix) + * @param {Object} [options] - Execution options + * @returns {Array|any} Results array or single value if simple mode + */ +pragma(source, options); + +interface PragmaOptions { + simple?: boolean; // Return single value instead of array (default: false) +} +``` + +**Usage Examples:** + +```javascript +// Get database information +const userVersion = db.pragma('user_version', { simple: true }); +console.log(userVersion); // Returns number directly + +// Get table information +const tableInfo = db.pragma('table_info(users)'); +console.log(tableInfo); +// Returns array of column descriptors: +// [ +// { cid: 0, name: 'id', type: 'INTEGER', notnull: 0, dflt_value: null, pk: 1 }, +// { cid: 1, name: 'name', type: 'TEXT', notnull: 1, dflt_value: null, pk: 0 }, +// ... +// ] + +// Get foreign key information +const foreignKeys = db.pragma('foreign_key_list(orders)'); +foreignKeys.forEach(fk => { + console.log(`${fk.from} references ${fk.table}.${fk.to}`); +}); + +// Database configuration +db.pragma('journal_mode = WAL'); // Enable WAL mode +db.pragma('synchronous = NORMAL'); // Set synchronous mode +db.pragma('cache_size = 10000'); // Set cache size + +// Get current settings +const journalMode = db.pragma('journal_mode', { simple: true }); +const pageSize = db.pragma('page_size', { simple: true }); +const cacheSize = db.pragma('cache_size', { simple: true }); + +console.log(`Journal mode: ${journalMode}, Page size: ${pageSize}, Cache size: ${cacheSize}`); +``` + +### Database Backup + +Create backups of the database to files with progress monitoring. + +```javascript { .api } +/** + * Backup database to file (async operation) + * @param {string} filename - Destination file path + * @param {Object} [options] - Backup options + * @returns {Promise} Promise resolving to backup completion info + */ +backup(filename, options); + +interface BackupOptions { + attached?: string; // Database name to backup (default: "main") + progress?: Function; // Progress callback function +} + +interface BackupProgress { + totalPages: number; // Total pages in database + remainingPages: number; // Pages remaining to backup (0 when complete) +} +``` + +**Usage Examples:** + +```javascript +// Simple backup +await db.backup('backup.db'); +console.log('Backup completed'); + +// Backup with progress monitoring +await db.backup('backup-with-progress.db', { + progress(info) { + const percent = ((info.totalPages - info.remainingPages) / info.totalPages * 100).toFixed(1); + console.log(`Backup progress: ${percent}% (${info.remainingPages} pages remaining)`); + + // Return custom page transfer rate (optional) + // return 100; // Transfer 100 pages at a time + } +}); + +// Backup attached database +db.exec("ATTACH DATABASE 'other.db' AS other"); +await db.backup('other-backup.db', { attached: 'other' }); + +// Backup with error handling +try { + await db.backup('/invalid/path/backup.db'); +} catch (error) { + console.error('Backup failed:', error.message); +} + +// Throttled backup for large databases +await db.backup('large-backup.db', { + progress(info) { + if (info.remainingPages > 0) { + // Transfer fewer pages at a time to avoid blocking + return 10; + } + } +}); +``` + +### Database Serialization + +Serialize database to Buffer for embedding or transmission. + +```javascript { .api } +/** + * Serialize database to Buffer + * @param {Object} [options] - Serialization options + * @returns {Buffer} Buffer containing complete serialized database + */ +serialize(options); + +interface SerializeOptions { + attached?: string; // Database name to serialize (default: "main") +} +``` + +**Usage Examples:** + +```javascript +// Serialize entire database to buffer +const serialized = db.serialize(); +console.log(`Database serialized to ${serialized.length} bytes`); + +// Save serialized database to file +const fs = require('fs'); +fs.writeFileSync('serialized-db.buf', serialized); + +// Restore database from serialized buffer +const restoredDb = new Database(serialized); + +// Serialize attached database +db.exec("ATTACH DATABASE 'temp.db' AS temp"); +const tempSerialized = db.serialize({ attached: 'temp' }); + +// Use serialization for database cloning +function cloneDatabase(sourceDb) { + const serialized = sourceDb.serialize(); + return new Database(serialized); +} + +const clonedDb = cloneDatabase(db); + +// Serialization with compression (using external library) +const zlib = require('zlib'); +const serialized = db.serialize(); +const compressed = zlib.gzipSync(serialized); +console.log(`Compressed from ${serialized.length} to ${compressed.length} bytes`); + +// Restore from compressed +const decompressed = zlib.gunzipSync(compressed); +const restoredFromCompressed = new Database(decompressed); +``` + +### Database Analysis and Introspection + +Use PRAGMA commands for comprehensive database analysis. + +```javascript { .api } +// Common introspection patterns using pragma() +``` + +**Schema Information:** + +```javascript +// Get all table names +const tables = db.pragma('table_list'); +const tableNames = tables.map(table => table.name); +console.log('Tables:', tableNames); + +// Get detailed table information +function getTableSchema(tableName) { + const columns = db.pragma(`table_info(${tableName})`); + const indexes = db.pragma(`index_list(${tableName})`); + const foreignKeys = db.pragma(`foreign_key_list(${tableName})`); + + return { + columns: columns.map(col => ({ + name: col.name, + type: col.type, + nullable: !col.notnull, + defaultValue: col.dflt_value, + primaryKey: !!col.pk + })), + indexes: indexes.map(idx => ({ + name: idx.name, + unique: !!idx.unique, + partial: !!idx.partial + })), + foreignKeys: foreignKeys.map(fk => ({ + column: fk.from, + referencesTable: fk.table, + referencesColumn: fk.to, + onUpdate: fk.on_update, + onDelete: fk.on_delete + })) + }; +} + +const userSchema = getTableSchema('users'); +console.log(userSchema); +``` + +**Database Statistics:** + +```javascript +// Get database size and page information +const pageCount = db.pragma('page_count', { simple: true }); +const pageSize = db.pragma('page_size', { simple: true }); +const freePages = db.pragma('freelist_count', { simple: true }); + +const totalSize = pageCount * pageSize; +const freeSize = freePages * pageSize; +const usedSize = totalSize - freeSize; + +console.log(`Database size: ${totalSize} bytes`); +console.log(`Used: ${usedSize} bytes (${(usedSize/totalSize*100).toFixed(1)}%)`); +console.log(`Free: ${freeSize} bytes (${(freeSize/totalSize*100).toFixed(1)}%)`); + +// Get compilation options +const compileOptions = db.pragma('compile_options'); +console.log('SQLite compile options:', compileOptions); + +// Check integrity +const integrityCheck = db.pragma('integrity_check'); +if (integrityCheck.length === 1 && integrityCheck[0] === 'ok') { + console.log('Database integrity OK'); +} else { + console.warn('Database integrity issues:', integrityCheck); +} +``` + +**Performance Analysis:** + +```javascript +// Analyze query performance +function analyzeQuery(sql) { + const queryPlan = db.pragma(`query_plan(${sql})`); + console.log('Query execution plan:'); + queryPlan.forEach(step => { + console.log(`${step.id}: ${step.detail}`); + }); +} + +analyzeQuery('SELECT * FROM users WHERE email = "test@example.com"'); + +// Get database statistics +const stats = db.pragma('stats'); +stats.forEach(stat => { + console.log(`${stat.table}: ${stat.index} (${stat.cells} cells)`); +}); +``` + +### Database Optimization + +Utility functions for database maintenance and optimization. + +**Vacuum and Analyze:** + +```javascript +// Optimize database storage +function optimizeDatabase() { + console.log('Starting database optimization...'); + + // Analyze all tables for query planner statistics + db.exec('ANALYZE'); + + // Rebuild database to reclaim space + db.exec('VACUUM'); + + console.log('Database optimization completed'); +} + +// Incremental vacuum (for WAL mode) +function incrementalVacuum(pages = 1000) { + db.pragma(`incremental_vacuum(${pages})`); +} + +// Auto-vacuum configuration +db.pragma('auto_vacuum = INCREMENTAL'); +``` + +**Checkpoint Management (WAL Mode):** + +```javascript +// Checkpoint WAL file +function checkpoint(mode = 'PASSIVE') { + const result = db.pragma(`wal_checkpoint(${mode})`, { simple: false }); + return { + busy: result[0], + log: result[1], + checkpointed: result[2] + }; +} + +// Different checkpoint modes +const passiveResult = checkpoint('PASSIVE'); // Non-blocking +const fullResult = checkpoint('FULL'); // Block until complete +const restartResult = checkpoint('RESTART'); // Reset WAL file + +console.log('Checkpoint results:', fullResult); +``` + +### Configuration Management + +Manage database-wide configuration settings. + +```javascript +// Performance tuning +function configureForPerformance() { + db.pragma('journal_mode = WAL'); // Enable WAL mode for better concurrency + db.pragma('synchronous = NORMAL'); // Balance safety and performance + db.pragma('cache_size = 10000'); // Increase cache size + db.pragma('temp_store = MEMORY'); // Use memory for temporary tables + db.pragma('mmap_size = 134217728'); // Enable memory mapping (128MB) +} + +// Safety-first configuration +function configureForSafety() { + db.pragma('journal_mode = DELETE'); // Traditional rollback journal + db.pragma('synchronous = FULL'); // Maximum durability + db.pragma('foreign_keys = ON'); // Enforce foreign key constraints +} + +// Get current configuration +function getCurrentConfig() { + return { + journalMode: db.pragma('journal_mode', { simple: true }), + synchronous: db.pragma('synchronous', { simple: true }), + cacheSize: db.pragma('cache_size', { simple: true }), + foreignKeys: db.pragma('foreign_keys', { simple: true }), + autoVacuum: db.pragma('auto_vacuum', { simple: true }), + mmapSize: db.pragma('mmap_size', { simple: true }) + }; +} + +console.log('Current configuration:', getCurrentConfig()); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/index.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/index.md new file mode 100644 index 000000000..f7835e368 --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/index.md @@ -0,0 +1,280 @@ +# better-sqlite3 + +better-sqlite3 is the fastest and simplest library for SQLite3 in Node.js, providing a synchronous API for high-performance database operations. Unlike the standard node-sqlite3 module which uses callbacks, better-sqlite3 offers direct return values and eliminates callback complexity while maintaining full SQLite feature support. + +## Package Information + +- **Package Name**: better-sqlite3 +- **Package Type**: npm +- **Language**: JavaScript (with TypeScript definitions) +- **Installation**: `npm install better-sqlite3` + +## Core Imports + +```javascript +const Database = require('better-sqlite3'); +``` + +For TypeScript: + +```typescript +import Database from 'better-sqlite3'; +// Or for named imports +import Database, { SqliteError } from 'better-sqlite3'; +``` + +## Basic Usage + +```javascript +const Database = require('better-sqlite3'); + +// Create/open database +const db = new Database('mydb.sqlite'); + +// Create table +db.exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)'); + +// Prepare and execute statements +const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); +const insertResult = insert.run('John Doe', 'john@example.com'); +console.log(insertResult.lastInsertRowid); // 1 + +// Query data +const getUser = db.prepare('SELECT * FROM users WHERE id = ?'); +const user = getUser.get(1); +console.log(user); // { id: 1, name: 'John Doe', email: 'john@example.com' } + +// Close database +db.close(); +``` + +## Architecture + +better-sqlite3 is built around several key components: + +- **Database Class**: Main interface for database connections and management +- **Statement Objects**: Prepared statements for efficient query execution +- **Transaction System**: Built-in transaction management with nested transaction support +- **Type System**: Automatic JavaScript-SQLite type conversions with safe integer support +- **Extension System**: Support for user-defined functions, aggregates, and virtual tables +- **Synchronous API**: Direct return values eliminating callback complexity + +## Capabilities + +### Database Management + +Core database connection and lifecycle management functionality for creating, configuring, and controlling SQLite database connections. + +```javascript { .api } +/** + * Creates a new database connection + * @param {string|Buffer} filename - Database file path, ":memory:" for in-memory, or Buffer for serialized database + * @param {Object} [options] - Database configuration options + * @returns {Database} Database instance + */ +function Database(filename, options); + +interface DatabaseOptions { + readonly?: boolean; // Open in readonly mode (default: false) + fileMustExist?: boolean; // Throw error if file doesn't exist (default: false) + timeout?: number; // Timeout in ms for locked database (default: 5000) + verbose?: Function; // Function called with every SQL execution + nativeBinding?: string | Object; // Path to native binding or binding object +} +``` + +[Database Management](./database-management.md) + +### Statement Execution + +Prepared statement functionality for efficient SQL query execution with parameter binding and result handling. + +```javascript { .api } +/** + * Creates a prepared statement from SQL string + * @param {string} sql - SQL query string + * @returns {Statement} Prepared statement object + */ +prepare(sql); + +interface Statement { + run(...params): RunResult; // Execute statement, return info + get(...params): Object; // Execute statement, return first row + all(...params): Object[]; // Execute statement, return all rows + iterate(...params): Iterator; // Execute statement, return iterator + bind(...params): Statement; // Permanently bind parameters + readonly reader: boolean; // Whether statement returns data +} + +interface RunResult { + changes: number; // Number of rows changed + lastInsertRowid: number; // ID of last inserted row +} +``` + +[Statement Execution](./statement-execution.md) + +### Transaction Management + +Transaction system providing ACID compliance with support for nested transactions using savepoints and multiple transaction types. + +```javascript { .api } +/** + * Creates a transaction function wrapper + * @param {Function} fn - Function to execute within transaction + * @returns {Function} Transaction function with transaction type variants + */ +transaction(fn); + +interface TransactionFunction { + (...args): any; // Default transaction (BEGIN) + deferred(...args): any; // Deferred transaction (BEGIN DEFERRED) + immediate(...args): any; // Immediate transaction (BEGIN IMMEDIATE) + exclusive(...args): any; // Exclusive transaction (BEGIN EXCLUSIVE) + readonly database: Database; // Associated database instance +} +``` + +[Transaction Management](./transaction-management.md) + +### Database Utilities + +Utility functions for database introspection, backup, serialization, and configuration management. + +```javascript { .api } +/** + * Execute PRAGMA commands for database configuration and introspection + * @param {string} source - PRAGMA command string + * @param {Object} [options] - Execution options + * @returns {Array|any} Results array or single value if simple mode + */ +pragma(source, options); + +/** + * Backup database to file + * @param {string} filename - Destination file path + * @param {Object} [options] - Backup options + * @returns {Promise} Promise resolving to backup progress info + */ +backup(filename, options); + +/** + * Serialize database to Buffer + * @param {Object} [options] - Serialization options + * @returns {Buffer} Serialized database buffer + */ +serialize(options); +``` + +[Database Utilities](./database-utilities.md) + +### User-Defined Functions + +Extension system for creating custom SQL functions, aggregate functions, and virtual tables to extend SQLite functionality. + +```javascript { .api } +/** + * Define user-defined function + * @param {string} name - Function name + * @param {Object} [options] - Function options + * @param {Function} fn - JavaScript function implementation + * @returns {Database} Database instance for chaining + */ +function(name, options, fn); + +/** + * Define user-defined aggregate function + * @param {string} name - Aggregate function name + * @param {Object} options - Aggregate configuration + * @returns {Database} Database instance for chaining + */ +aggregate(name, options); + +/** + * Define virtual table module + * @param {string} name - Module name + * @param {Function|Object} factory - Factory function or table definition + * @returns {Database} Database instance for chaining + */ +table(name, factory); +``` + +[User-Defined Functions](./user-defined-functions.md) + +## Types + +```javascript { .api } +class Database { + constructor(filename, options); + + // Core methods + prepare(sql): Statement; + transaction(fn): TransactionFunction; + exec(sql): Database; + close(): Database; + + // Database utilities + pragma(source, options): Array | any; + backup(filename, options): Promise; + serialize(options): Buffer; + + // Extensions + function(name, options, fn): Database; + aggregate(name, options): Database; + table(name, factory): Database; + loadExtension(path, entrypoint): Database; + + // Configuration + defaultSafeIntegers(enabled): Database; + unsafeMode(enabled): Database; + + // Properties (read-only) + readonly name: string; // Database filename + readonly open: boolean; // Connection status + readonly inTransaction: boolean; // Transaction status + readonly readonly: boolean; // Readonly mode status + readonly memory: boolean; // In-memory database status +} + +class Statement { + // Execution methods + run(...params): RunResult; + get(...params): Object | undefined; + all(...params): Object[]; + iterate(...params): Iterator; + + // Configuration + bind(...params): Statement; + pluck(enabled): Statement; + expand(enabled): Statement; + raw(enabled): Statement; + safeIntegers(enabled): Statement; + columns(): ColumnDescriptor[]; + + // Properties (read-only) + readonly reader: boolean; // Whether statement returns data + readonly busy: boolean; // Whether statement is executing + readonly source: string; // Original SQL string used to create statement + readonly database: Database; // Associated database instance +} + +class SqliteError extends Error { + constructor(message, code); + readonly name: string; // Always "SqliteError" + readonly code: string; // SQLite error code + readonly message: string; // Error message +} + +interface RunResult { + changes: number; // Number of rows changed + lastInsertRowid: number; // ID of last inserted row +} + +interface ColumnDescriptor { + name: string; // Column name in result set + column: string | null; // Original column name + table: string | null; // Table name + database: string | null; // Database name + type: string | null; // Column data type +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/statement-execution.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/statement-execution.md new file mode 100644 index 000000000..765ff46e9 --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/statement-execution.md @@ -0,0 +1,354 @@ +# Statement Execution + +Prepared statement functionality for efficient SQL query execution with parameter binding and result handling. + +## Capabilities + +### Statement Preparation + +Create prepared statements from SQL strings for efficient repeated execution. + +```javascript { .api } +/** + * Creates a prepared statement from SQL string + * @param {string} sql - SQL query string with optional parameter placeholders + * @returns {Statement} Prepared statement object + */ +prepare(sql); +``` + +**Usage Examples:** + +```javascript +// Prepare INSERT statement +const insertUser = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + +// Prepare SELECT statement with named parameters +const getUserByEmail = db.prepare('SELECT * FROM users WHERE email = @email'); + +// Prepare UPDATE statement with mixed parameters +const updateUser = db.prepare('UPDATE users SET name = ? WHERE id = $id'); + +// Prepare complex query +const getOrdersWithDetails = db.prepare(` + SELECT o.id, o.total, u.name as customer_name, + COUNT(oi.id) as item_count + FROM orders o + JOIN users u ON o.user_id = u.id + LEFT JOIN order_items oi ON o.id = oi.order_id + WHERE o.created_at > ? + GROUP BY o.id + ORDER BY o.created_at DESC +`); +``` + +### Statement Execution Methods + +Execute prepared statements and retrieve results in different formats. + +```javascript { .api } +/** + * Execute statement for data modification, return info about changes + * @param {...any} params - Parameters to bind to statement + * @returns {RunResult} Object with changes and lastInsertRowid + */ +run(...params); + +/** + * Execute statement and return first row + * @param {...any} params - Parameters to bind to statement + * @returns {Object|undefined} First row object or undefined if no results + */ +get(...params); + +/** + * Execute statement and return all rows + * @param {...any} params - Parameters to bind to statement + * @returns {Object[]} Array of row objects + */ +all(...params); + +/** + * Execute statement and return iterator for memory-efficient processing + * @param {...any} params - Parameters to bind to statement + * @returns {Iterator} Iterator yielding row objects + */ +iterate(...params); + +interface RunResult { + changes: number; // Number of rows changed by the operation + lastInsertRowid: number; // Row ID of last inserted row (0 if none) +} +``` + +**Usage Examples:** + +```javascript +// Using run() for data modification +const insertUser = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); +const result = insertUser.run('Alice Smith', 'alice@example.com'); +console.log(result.changes); // 1 +console.log(result.lastInsertRowid); // 1 (the new user's ID) + +// Using get() for single row retrieval +const getUser = db.prepare('SELECT * FROM users WHERE id = ?'); +const user = getUser.get(1); +console.log(user); // { id: 1, name: 'Alice Smith', email: 'alice@example.com' } + +// Using all() for multiple rows +const getAllUsers = db.prepare('SELECT * FROM users ORDER BY name'); +const users = getAllUsers.all(); +console.log(users.length); // Number of users +users.forEach(user => console.log(user.name)); + +// Using iterate() for memory-efficient processing of large result sets +const getActiveOrders = db.prepare('SELECT * FROM orders WHERE status = ?'); +for (const order of getActiveOrders.iterate('active')) { + console.log(`Order ${order.id}: $${order.total}`); + // Process one order at a time without loading all into memory +} +``` + +### Parameter Binding + +Bind parameters to prepared statements for secure and efficient execution. + +```javascript { .api } +/** + * Permanently bind parameters to statement + * @param {...any} params - Parameters to bind (positional or named) + * @returns {Statement} Statement instance for chaining + */ +bind(...params); +``` + +**Parameter Binding Styles:** + +```javascript +// Positional parameters with ? +const stmt1 = db.prepare('SELECT * FROM users WHERE age > ? AND city = ?'); +stmt1.run(25, 'New York'); // Temporary binding +stmt1.bind(25, 'New York'); // Permanent binding + +// Named parameters with @name, :name, or $name +const stmt2 = db.prepare('SELECT * FROM users WHERE age > @minAge AND city = @city'); +stmt2.run({ minAge: 25, city: 'New York' }); + +// Object binding for named parameters +const stmt3 = db.prepare('INSERT INTO users (name, email, age) VALUES (@name, @email, @age)'); +stmt3.run({ + name: 'Bob Wilson', + email: 'bob@example.com', + age: 30 +}); + +// Array binding for positional parameters +const stmt4 = db.prepare('INSERT INTO users (name, email, age) VALUES (?, ?, ?)'); +stmt4.run(['Charlie Brown', 'charlie@example.com', 28]); + +// Permanent binding prevents further parameter passing +const boundStmt = db.prepare('SELECT * FROM users WHERE status = ?'); +boundStmt.bind('active'); +// boundStmt.run('inactive'); // Would throw TypeError +``` + +### Statement Configuration + +Configure statement behavior for result formatting and data handling. + +```javascript { .api } +/** + * Enable/disable column plucking (return only first column value) + * @param {boolean} enabled - Enable plucking mode + * @returns {Statement} Statement instance for chaining + */ +pluck(enabled); + +/** + * Enable/disable row expansion (return nested objects by table) + * @param {boolean} enabled - Enable expansion mode + * @returns {Statement} Statement instance for chaining + */ +expand(enabled); + +/** + * Enable/disable raw mode (return arrays instead of objects) + * @param {boolean} enabled - Enable raw mode + * @returns {Statement} Statement instance for chaining + */ +raw(enabled); + +/** + * Enable/disable safe integer mode for this statement + * @param {boolean} enabled - Enable safe integers (return BigInt for large numbers) + * @returns {Statement} Statement instance for chaining + */ +safeIntegers(enabled); +``` + +**Usage Examples:** + +```javascript +// Pluck mode - return only first column value +const getName = db.prepare('SELECT name FROM users WHERE id = ?').pluck(); +const name = getName.get(1); // Returns "Alice Smith" instead of { name: "Alice Smith" } + +// Raw mode - return arrays instead of objects +const getUserRaw = db.prepare('SELECT id, name, email FROM users WHERE id = ?').raw(); +const userData = getUserRaw.get(1); // Returns [1, "Alice Smith", "alice@example.com"] + +// Expand mode - nested objects by table +const getOrderWithUser = db.prepare(` + SELECT o.id, o.total, u.name, u.email + FROM orders o + JOIN users u ON o.user_id = u.id + WHERE o.id = ? +`).expand(); +const result = getOrderWithUser.get(1); +// Returns: { orders: { id: 1, total: 99.99 }, users: { name: "Alice", email: "alice@example.com" } } + +// Safe integers for handling large numbers +const getBigNumber = db.prepare('SELECT big_integer_column FROM table WHERE id = ?').safeIntegers(); +const bigNum = getBigNumber.get(1); // Returns BigInt instead of potentially unsafe number + +// Chain configuration methods +const configuredStmt = db.prepare('SELECT COUNT(*) as count FROM users') + .pluck() // Only return the count value + .safeIntegers(true); // Use BigInt for large counts +const userCount = configuredStmt.get(); // Returns BigInt directly +``` + +### Statement Metadata + +Retrieve metadata information about prepared statements. + +```javascript { .api } +/** + * Get column information for SELECT statements + * @returns {ColumnDescriptor[]} Array of column descriptors + */ +columns(); + +interface ColumnDescriptor { + name: string; // Column name in result set + column: string | null; // Original column name (null for expressions) + table: string | null; // Source table name (null for expressions) + database: string | null; // Database name (typically "main") + type: string | null; // Declared column type (null for expressions) +} +``` + +**Usage Examples:** + +```javascript +// Get column metadata +const stmt = db.prepare('SELECT u.id, u.name, COUNT(*) as order_count FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id'); +const columns = stmt.columns(); + +columns.forEach(col => { + console.log(`Column: ${col.name}`); + console.log(` Original: ${col.column}`); + console.log(` Table: ${col.table}`); + console.log(` Type: ${col.type}`); +}); + +// Output: +// Column: id +// Original: id +// Table: users +// Type: INTEGER +// Column: name +// Original: name +// Table: users +// Type: TEXT +// Column: order_count +// Original: null +// Table: null +// Type: null +``` + +### Statement Properties + +Read-only properties providing statement information. + +```javascript { .api } +interface StatementProperties { + readonly reader: boolean; // Whether statement returns data (SELECT vs INSERT/UPDATE/etc) + readonly busy: boolean; // Whether statement is currently executing + readonly database: Database; // Associated database instance +} +``` + +**Usage Examples:** + +```javascript +const selectStmt = db.prepare('SELECT * FROM users'); +const insertStmt = db.prepare('INSERT INTO users (name) VALUES (?)'); + +console.log(selectStmt.reader); // true (SELECT statement) +console.log(insertStmt.reader); // false (INSERT statement) + +// Can't use get/all/iterate on non-reader statements +try { + insertStmt.get(); // Throws TypeError +} catch (error) { + console.log(error.message); // "This statement does not return data" +} + +// Can't use columns() on non-reader statements +try { + insertStmt.columns(); // Throws TypeError +} catch (error) { + console.log(error.message); // "This statement does not return data" +} + +console.log(selectStmt.database === db); // true +console.log(selectStmt.busy); // false (when not executing) +``` + +## Data Type Conversions + +better-sqlite3 automatically converts between JavaScript and SQLite data types: + +**JavaScript to SQLite:** +- `null`, `undefined` → NULL +- `string` → TEXT +- `number` → INTEGER or REAL +- `bigint` → INTEGER (when safe integers enabled) +- `boolean` → INTEGER (0 or 1) +- `Buffer` → BLOB +- `Date` → TEXT (ISO string) or INTEGER (timestamp) + +**SQLite to JavaScript:** +- NULL → `null` +- INTEGER → `number` or `bigint` (when safe integers enabled) +- REAL → `number` +- TEXT → `string` +- BLOB → `Buffer` + +**Usage Examples:** + +```javascript +// Inserting different data types +const insertData = db.prepare('INSERT INTO mixed_data (text_col, int_col, real_col, blob_col, bool_col) VALUES (?, ?, ?, ?, ?)'); +insertData.run( + 'Hello World', // TEXT + 42, // INTEGER + 3.14159, // REAL + Buffer.from('binary data'), // BLOB + true // INTEGER (1) +); + +// Date handling +const insertDate = db.prepare('INSERT INTO events (name, created_at) VALUES (?, ?)'); +insertDate.run('Event Name', new Date()); // Date becomes TEXT ISO string + +// Large integer handling with safe integers +db.defaultSafeIntegers(true); +const insertBigInt = db.prepare('INSERT INTO big_numbers (value) VALUES (?)'); +insertBigInt.run(9007199254740992n); // BigInt preserved as INTEGER + +const getBigInt = db.prepare('SELECT value FROM big_numbers WHERE id = ?'); +const result = getBigInt.get(1); +console.log(typeof result.value); // "bigint" +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/transaction-management.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/transaction-management.md new file mode 100644 index 000000000..d006ddfa5 --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/transaction-management.md @@ -0,0 +1,318 @@ +# Transaction Management + +Transaction system providing ACID compliance with support for nested transactions using savepoints and multiple transaction types. + +## Capabilities + +### Transaction Creation + +Create transaction wrapper functions that automatically handle BEGIN/COMMIT/ROLLBACK operations. + +```javascript { .api } +/** + * Creates a transaction function wrapper + * @param {Function} fn - Function to execute within transaction + * @returns {TransactionFunction} Transaction function with transaction type variants + */ +transaction(fn); + +interface TransactionFunction { + (...args): any; // Default transaction using BEGIN + deferred(...args): any; // Deferred transaction using BEGIN DEFERRED + immediate(...args): any; // Immediate transaction using BEGIN IMMEDIATE + exclusive(...args): any; // Exclusive transaction using BEGIN EXCLUSIVE + readonly database: Database; // Associated database instance +} +``` + +**Usage Examples:** + +```javascript +// Create transaction function +const insertMany = db.transaction((users) => { + const insert = db.prepare('INSERT INTO users (name, email) VALUES (@name, @email)'); + for (const user of users) { + insert.run(user); + } +}); + +// Execute transaction +insertMany([ + { name: 'Alice', email: 'alice@example.com' }, + { name: 'Bob', email: 'bob@example.com' }, + { name: 'Charlie', email: 'charlie@example.com' } +]); + +// All users inserted atomically, or none if any fails +``` + +### Transaction Types + +Different transaction types provide various levels of locking and concurrency control. + +```javascript { .api } +// Transaction type variants +transactionFunction(); // BEGIN (same as deferred) +transactionFunction.deferred(); // BEGIN DEFERRED (default SQLite behavior) +transactionFunction.immediate(); // BEGIN IMMEDIATE (acquire reserved lock immediately) +transactionFunction.exclusive(); // BEGIN EXCLUSIVE (acquire exclusive lock immediately) +``` + +**Transaction Type Behaviors:** + +```javascript +const updateInventory = db.transaction((items) => { + const update = db.prepare('UPDATE inventory SET quantity = quantity - ? WHERE item_id = ?'); + for (const item of items) { + update.run(item.quantity, item.id); + } +}); + +// Deferred transaction - acquire locks as needed (default) +updateInventory.deferred(items); + +// Immediate transaction - acquire reserved lock immediately +// (prevents other writers from starting) +updateInventory.immediate(items); + +// Exclusive transaction - acquire exclusive lock immediately +// (prevents all other connections from reading or writing) +updateInventory.exclusive(items); +``` + +### Nested Transactions + +Transactions can be nested using SQLite savepoints for complex error handling scenarios. + +```javascript { .api } +// Nested transactions automatically use savepoints +// Inner transaction failures roll back to savepoint, not beginning +``` + +**Usage Examples:** + +```javascript +const insertUser = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); +const insertProfile = db.prepare('INSERT INTO profiles (user_id, bio) VALUES (?, ?)'); +const insertPreferences = db.prepare('INSERT INTO preferences (user_id, theme) VALUES (?, ?)'); + +// Outer transaction +const createUserWithProfile = db.transaction((userData) => { + // Insert user + const userResult = insertUser.run(userData.name, userData.email); + const userId = userResult.lastInsertRowid; + + // Inner transaction for profile creation + const createProfile = db.transaction((profileData) => { + insertProfile.run(userId, profileData.bio); + + if (profileData.preferences) { + // Nested inner transaction for preferences + const setPreferences = db.transaction((prefs) => { + insertPreferences.run(userId, prefs.theme); + if (prefs.theme === 'invalid') { + throw new Error('Invalid theme'); // This will rollback only preferences + } + }); + + setPreferences(profileData.preferences); + } + }); + + try { + createProfile(userData.profile); + } catch (error) { + console.log('Profile creation failed, but user was created'); + // User insert is preserved, only profile operations rolled back + } +}); + +// Execute the nested transaction +createUserWithProfile({ + name: 'John Doe', + email: 'john@example.com', + profile: { + bio: 'Software developer', + preferences: { theme: 'dark' } + } +}); +``` + +### Transaction Error Handling + +Transactions automatically handle errors with proper rollback behavior. + +```javascript { .api } +// Automatic rollback on any thrown error +// Error propagates normally after rollback +// Nested transactions use savepoints for partial rollback +``` + +**Usage Examples:** + +```javascript +const transferFunds = db.transaction((fromAccount, toAccount, amount) => { + const debit = db.prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?'); + const credit = db.prepare('UPDATE accounts SET balance = balance + ? WHERE id = ?'); + const getBalance = db.prepare('SELECT balance FROM accounts WHERE id = ?'); + + // Check sufficient funds + const fromBalance = getBalance.get(fromAccount).balance; + if (fromBalance < amount) { + throw new Error('Insufficient funds'); // Transaction will rollback + } + + // Perform transfer + debit.run(amount, fromAccount); + credit.run(amount, toAccount); + + // Verify the transfer + const newFromBalance = getBalance.get(fromAccount).balance; + const newToBalance = getBalance.get(toAccount).balance; + + return { + fromBalance: newFromBalance, + toBalance: newToBalance, + transferred: amount + }; +}); + +try { + const result = transferFunds(1, 2, 100); + console.log('Transfer completed:', result); +} catch (error) { + console.log('Transfer failed:', error.message); + // Database state unchanged due to automatic rollback +} +``` + +### Transaction Function Properties + +Transaction functions expose properties for introspection and database access. + +```javascript { .api } +interface TransactionFunction { + readonly database: Database; // Associated database instance + // All transaction type variants (deferred, immediate, exclusive) have same properties +} +``` + +**Usage Examples:** + +```javascript +const batchInsert = db.transaction((data) => { + // Function implementation +}); + +// Access the associated database +console.log(batchInsert.database === db); // true + +// All transaction variants share the same database reference +console.log(batchInsert.deferred.database === db); // true +console.log(batchInsert.immediate.database === db); // true +console.log(batchInsert.exclusive.database === db); // true + +// Check if currently in transaction during execution +const checkTransactionStatus = db.transaction(() => { + console.log(db.inTransaction); // true during transaction execution +}); + +checkTransactionStatus(); +console.log(db.inTransaction); // false after transaction completes +``` + +### Transaction Best Practices + +Guidelines for effective transaction usage and performance optimization. + +**Performance Considerations:** + +```javascript +// Good: Batch multiple operations in a single transaction +const batchUserInsert = db.transaction((users) => { + const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + for (const user of users) { + insert.run(user.name, user.email); + } +}); + +// Bad: Individual transactions for each operation (slow) +function insertUsersSlow(users) { + const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + for (const user of users) { + const singleInsert = db.transaction(() => { + insert.run(user.name, user.email); + }); + singleInsert(); // Creates transaction overhead for each insert + } +} + +// Good: Short-lived transactions +const quickUpdate = db.transaction((id, newValue) => { + db.prepare('UPDATE table SET value = ? WHERE id = ?').run(newValue, id); +}); + +// Avoid: Long-running transactions that hold locks +const avoidLongTransaction = db.transaction(() => { + // Don't do this - holds database locks too long + for (let i = 0; i < 1000000; i++) { + // Long-running computation + heavyComputation(); + } + db.prepare('INSERT INTO results VALUES (?)').run(result); +}); +``` + +**Error Handling Patterns:** + +```javascript +// Pattern: Specific error handling with graceful degradation +const safeUserCreation = db.transaction((userData) => { + const insertUser = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)'); + const insertAuditLog = db.prepare('INSERT INTO audit_log (action, details) VALUES (?, ?)'); + + try { + const result = insertUser.run(userData.name, userData.email); + + // Nested transaction for audit log (can fail without affecting user creation) + const logAudit = db.transaction(() => { + insertAuditLog.run('user_created', JSON.stringify(userData)); + }); + + try { + logAudit(); + } catch (auditError) { + console.warn('Audit logging failed:', auditError.message); + // User creation still succeeds + } + + return result.lastInsertRowid; + } catch (error) { + console.error('User creation failed:', error.message); + throw error; // Re-throw to trigger rollback + } +}); +``` + +### Manual Transaction Control + +While transaction functions are recommended, manual transaction control is also possible. + +```javascript +// Manual transaction control (not recommended with transaction functions) +db.exec('BEGIN'); +try { + db.prepare('INSERT INTO users (name) VALUES (?)').run('John'); + db.prepare('INSERT INTO profiles (user_id) VALUES (?)').run(1); + db.exec('COMMIT'); +} catch (error) { + db.exec('ROLLBACK'); + throw error; +} + +// Warning: Don't mix manual control with transaction functions +const mixedApproach = db.transaction(() => { + // Don't use raw COMMIT/ROLLBACK inside transaction functions + // db.exec('COMMIT'); // This will cause issues +}); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/docs/user-defined-functions.md b/.tessl/tiles/tessl/npm-better-sqlite3/docs/user-defined-functions.md new file mode 100644 index 000000000..1c2f6f753 --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/docs/user-defined-functions.md @@ -0,0 +1,410 @@ +# User-Defined Functions + +Extension system for creating custom SQL functions, aggregate functions, and virtual tables to extend SQLite functionality. + +## Capabilities + +### User-Defined Functions + +Create custom SQL functions that can be called from within SQL queries. + +```javascript { .api } +/** + * Define user-defined function + * @param {string} name - Function name (used in SQL queries) + * @param {Object} [options] - Function configuration options + * @param {Function} fn - JavaScript function implementation + * @returns {Database} Database instance for chaining + */ +function(name, options, fn); + +interface FunctionOptions { + safeIntegers?: boolean; // Use safe integers for this function (default: database setting) + deterministic?: boolean; // Function is deterministic (default: false) + directOnly?: boolean; // Function can only be called directly, not in triggers/views (default: false) + varargs?: boolean; // Function accepts variable arguments (default: false) +} +``` + +**Usage Examples:** + +```javascript +// Simple string function +db.function('reverse', (str) => { + return typeof str === 'string' ? str.split('').reverse().join('') : null; +}); + +// Use in SQL query +const result = db.prepare('SELECT reverse(name) as reversed_name FROM users').all(); +console.log(result); // [{ reversed_name: 'ecilA' }, { reversed_name: 'boB' }, ...] + +// Math function with multiple parameters +db.function('pythagoras', (a, b) => { + if (typeof a !== 'number' || typeof b !== 'number') return null; + return Math.sqrt(a * a + b * b); +}); + +const distance = db.prepare('SELECT pythagoras(3, 4) as distance').get(); +console.log(distance.distance); // 5 + +// Function with options +db.function('random_int', { + deterministic: false, // Result can vary between calls + directOnly: true // Can't be used in triggers or views +}, (min, max) => { + if (typeof min !== 'number' || typeof max !== 'number') return null; + return Math.floor(Math.random() * (max - min + 1)) + min; +}); + +// Variable arguments function +db.function('concat_with_separator', { + varargs: true +}, (separator, ...args) => { + if (typeof separator !== 'string') return null; + return args.filter(arg => arg != null).join(separator); +}); + +const concatenated = db.prepare("SELECT concat_with_separator(' | ', name, email, city) as info FROM users").all(); +``` + +### Aggregate Functions + +Create custom aggregate functions for GROUP BY operations and window functions. + +```javascript { .api } +/** + * Define user-defined aggregate function + * @param {string} name - Aggregate function name + * @param {Object} options - Aggregate configuration (required) + * @returns {Database} Database instance for chaining + */ +aggregate(name, options); + +interface AggregateOptions { + start?: any; // Initial accumulator value (default: null) + step: Function; // Step function called for each row (required) + inverse?: Function; // Inverse function for window functions (optional) + result?: Function; // Final result transformation function (optional) + safeIntegers?: boolean; // Use safe integers (default: database setting) + deterministic?: boolean; // Function is deterministic (default: false) + directOnly?: boolean; // Function can only be called directly (default: false) + varargs?: boolean; // Function accepts variable arguments (default: false) +} +``` + +**Usage Examples:** + +```javascript +// String concatenation aggregate +db.aggregate('group_concat_custom', { + start: '', + step: (accumulator, value) => { + if (value == null) return accumulator; + return accumulator === '' ? String(value) : accumulator + ', ' + String(value); + }, + result: (accumulator) => accumulator || null +}); + +const groupedNames = db.prepare('SELECT group_concat_custom(name) as names FROM users').get(); +console.log(groupedNames.names); // "Alice, Bob, Charlie" + +// Mathematical aggregate - geometric mean +db.aggregate('geometric_mean', { + start: { product: 1, count: 0 }, + step: (accumulator, value) => { + if (typeof value !== 'number' || value <= 0) return accumulator; + return { + product: accumulator.product * value, + count: accumulator.count + 1 + }; + }, + result: (accumulator) => { + if (accumulator.count === 0) return null; + return Math.pow(accumulator.product, 1 / accumulator.count); + } +}); + +const geometricMean = db.prepare('SELECT geometric_mean(value) as geo_mean FROM measurements').get(); + +// Window function with inverse (for sliding windows) +db.aggregate('running_average', { + start: { sum: 0, count: 0 }, + step: (accumulator, value) => { + if (typeof value !== 'number') return accumulator; + return { + sum: accumulator.sum + value, + count: accumulator.count + 1 + }; + }, + inverse: (accumulator, value) => { + if (typeof value !== 'number') return accumulator; + return { + sum: accumulator.sum - value, + count: accumulator.count - 1 + }; + }, + result: (accumulator) => { + return accumulator.count > 0 ? accumulator.sum / accumulator.count : null; + } +}); + +// Use as window function +const runningAverage = db.prepare(` + SELECT value, + running_average(value) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as avg_3 + FROM measurements + ORDER BY id +`).all(); + +// Complex aggregate with multiple parameters +db.aggregate('weighted_average', { + start: { weightedSum: 0, totalWeight: 0 }, + step: (accumulator, value, weight) => { + if (typeof value !== 'number' || typeof weight !== 'number' || weight <= 0) { + return accumulator; + } + return { + weightedSum: accumulator.weightedSum + (value * weight), + totalWeight: accumulator.totalWeight + weight + }; + }, + result: (accumulator) => { + return accumulator.totalWeight > 0 ? accumulator.weightedSum / accumulator.totalWeight : null; + } +}); +``` + +### Virtual Tables + +Create virtual tables that generate data dynamically or interface with external data sources. + +```javascript { .api } +/** + * Define virtual table module + * @param {string} name - Module name + * @param {Function|Object} factory - Factory function or eponymous table definition + * @returns {Database} Database instance for chaining + */ +table(name, factory); + +// Factory function signature +interface TableFactory { + (moduleName: string, databaseName: string, tableName: string, ...args): TableDefinition; +} + +// Table definition object +interface TableDefinition { + columns: string[]; // Column names (required) + rows: GeneratorFunction; // Generator function yielding rows (required) + parameters?: string[]; // Parameter names (optional, inferred from rows.length) + safeIntegers?: boolean; // Use safe integers (default: database setting) + directOnly?: boolean; // Table can only be accessed directly (default: false) +} +``` + +**Usage Examples:** + +```javascript +// Simple eponymous-only virtual table (no factory) +db.table('fibonacci', { + columns: ['value', 'position'], + *rows(limit = 10) { + let a = 0, b = 1, position = 0; + while (position < limit) { + yield [a, position]; + [a, b] = [b, a + b]; + position++; + } + } +}); + +// Use the virtual table +const fibNumbers = db.prepare('SELECT * FROM fibonacci(15)').all(); +console.log(fibNumbers); // First 15 Fibonacci numbers + +// Factory-based virtual table for flexibility +db.table('sequence_generator', function(moduleName, databaseName, tableName, type) { + return { + columns: ['value', 'index'], + parameters: ['start', 'end', 'step'], + *rows(start, end, step = 1) { + let index = 0; + for (let value = start; value <= end; value += step) { + if (type === 'even' && value % 2 !== 0) continue; + if (type === 'odd' && value % 2 === 0) continue; + yield { value, index: index++ }; + } + } + }; +}); + +// Create specific table instances +db.exec('CREATE VIRTUAL TABLE even_numbers USING sequence_generator(even)'); +db.exec('CREATE VIRTUAL TABLE odd_numbers USING sequence_generator(odd)'); + +// Query the virtual tables +const evenNumbers = db.prepare('SELECT * FROM even_numbers(2, 20, 2)').all(); +const oddNumbers = db.prepare('SELECT * FROM odd_numbers(1, 19, 2)').all(); + +// Complex virtual table with external data +db.table('file_system', { + columns: ['name', 'size', 'type', 'modified'], + parameters: ['directory'], + *rows(directory = '.') { + const fs = require('fs'); + const path = require('path'); + + try { + const entries = fs.readdirSync(directory, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + const stats = fs.statSync(fullPath); + + yield { + name: entry.name, + size: stats.size, + type: entry.isDirectory() ? 'directory' : 'file', + modified: stats.mtime.toISOString() + }; + } + } catch (error) { + // Handle directory access errors gracefully + console.warn(`Cannot read directory ${directory}:`, error.message); + } + } +}); + +// Query file system +const files = db.prepare(` + SELECT name, size, type + FROM file_system('/usr/local/bin') + WHERE type = 'file' AND size > 1000 + ORDER BY size DESC +`).all(); + +// Virtual table with JSON data processing +db.table('json_parser', { + columns: ['key', 'value', 'type'], + parameters: ['json_string', 'path'], + *rows(jsonString, path = '$') { + try { + const data = JSON.parse(jsonString); + + function* processObject(obj, currentPath) { + for (const [key, value] of Object.entries(obj)) { + const fullPath = currentPath === '$' ? `$.${key}` : `${currentPath}.${key}`; + + if (path === '$' || fullPath.startsWith(path)) { + yield { + key: fullPath, + value: typeof value === 'object' ? JSON.stringify(value) : String(value), + type: Array.isArray(value) ? 'array' : typeof value + }; + } + + if (typeof value === 'object' && value !== null) { + yield* processObject(value, fullPath); + } + } + } + + yield* processObject(data, '$'); + } catch (error) { + yield { key: 'error', value: error.message, type: 'error' }; + } + } +}); + +// Parse JSON data +const jsonData = '{"users": [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]}'; +const parsedData = db.prepare(` + SELECT key, value, type + FROM json_parser(?, '$.users') + WHERE type != 'object' +`).all(jsonData); +``` + +### Function and Table Management + +Utilities for managing user-defined functions and virtual tables. + +**Function Replacement:** + +```javascript +// Functions can be replaced by redefining +db.function('my_function', () => 'version 1'); +let result1 = db.prepare('SELECT my_function() as result').get(); +console.log(result1.result); // "version 1" + +db.function('my_function', () => 'version 2'); +let result2 = db.prepare('SELECT my_function() as result').get(); +console.log(result2.result); // "version 2" + +// Remove function by providing null +db.function('my_function', null); +// Now my_function() is no longer available +``` + +**Error Handling in Functions:** + +```javascript +// Handle errors gracefully in user-defined functions +db.function('safe_divide', (a, b) => { + if (typeof a !== 'number' || typeof b !== 'number') return null; + if (b === 0) return null; // Return null for division by zero + return a / b; +}); + +// Function that throws errors +db.function('strict_divide', (a, b) => { + if (typeof a !== 'number' || typeof b !== 'number') { + throw new Error('Arguments must be numbers'); + } + if (b === 0) { + throw new Error('Division by zero'); + } + return a / b; +}); + +// Errors in functions become SQL errors +try { + db.prepare('SELECT strict_divide(10, 0)').get(); +} catch (error) { + console.log(error.message); // "Division by zero" +} +``` + +**Performance Considerations:** + +```javascript +// Use deterministic flag for cacheable functions +db.function('expensive_calculation', { + deterministic: true // SQLite can cache results +}, (input) => { + // Expensive computation that always returns same result for same input + return heavyMathOperation(input); +}); + +// Use directOnly for security-sensitive functions +db.function('get_secret', { + directOnly: true // Prevents use in triggers, views, or stored procedures +}, () => { + return process.env.SECRET_KEY; +}); + +// Optimize virtual tables for large datasets +db.table('large_dataset', { + columns: ['id', 'data'], + *rows(limit = 1000000) { + for (let i = 0; i < limit; i++) { + // Yield data incrementally to avoid memory issues + yield { id: i, data: `record_${i}` }; + + // Optional: yield control periodically for very large datasets + if (i % 10000 === 0) { + setImmediate(() => {}); // Allow event loop to process other tasks + } + } + } +}); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-better-sqlite3/tile.json b/.tessl/tiles/tessl/npm-better-sqlite3/tile.json new file mode 100644 index 000000000..92b95ea6a --- /dev/null +++ b/.tessl/tiles/tessl/npm-better-sqlite3/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/npm-better-sqlite3", + "version": "12.2.0", + "docs": "docs/index.md", + "describes": "pkg:npm/better-sqlite3@12.2.0", + "summary": "The fastest and simplest library for SQLite3 in Node.js with synchronous API for high-performance database operations" +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/cli-usage.md b/.tessl/tiles/tessl/npm-jest/docs/cli-usage.md new file mode 100644 index 000000000..a6acf231a --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/cli-usage.md @@ -0,0 +1,407 @@ +# CLI Usage + +Jest provides a comprehensive command-line interface with over 70 options for controlling test execution, coverage collection, watch mode, output formatting, and project configuration. + +## Basic CLI Usage + +Jest can be run from the command line with various options: + +```bash +# Run all tests +jest + +# Run tests matching a pattern +jest MyComponent + +# Run tests in a specific directory +jest src/components + +# Run tests with coverage +jest --coverage + +# Run tests in watch mode +jest --watch +``` + +## CLI Options Reference + +### Test Execution Options + +Control how tests are discovered, executed, and filtered. + +```bash +# Stop after N test failures +jest --bail +jest --bail=3 + +# Find tests related to specified files +jest --findRelatedTests src/utils.js src/components/Button.js + +# List all tests Jest will run without executing them +jest --listTests + +# Only run tests related to changed files (requires git) +jest --onlyChanged +jest -o + +# Run only tests that failed in previous execution +jest --onlyFailures +jest -f + +# Don't fail when no tests are found +jest --passWithNoTests + +# Run tests serially in current process instead of parallel workers +jest --runInBand +jest -i + +# Use exact file paths instead of patterns +jest --runTestsByPath path/to/test1.js path/to/test2.js + +# Run tests matching name pattern (regex) +jest --testNamePattern="should add" +jest -t "user login" + +# Regexp patterns for test file paths +jest --testPathPatterns="__tests__.*\.js$" + +# Override testRegex configuration +jest --testRegex=".*\.(test|spec)\.(js|ts)$" + +# Set default test timeout in milliseconds +jest --testTimeout=10000 +``` + +### Watch Mode Options + +Configure file watching and automatic test re-execution. + +```bash +# Watch files and rerun related tests on changes +jest --watch + +# Watch files and rerun all tests on changes +jest --watchAll + +# Ignore patterns for watch mode +jest --watchPathIgnorePatterns="node_modules" --watchPathIgnorePatterns="build" +``` + +## Testing Options + +### Test Selection and Filtering + +```bash +# Run only tests that failed in the previous run +jest --onlyFailures + +# Run only tests related to changed files (requires git) +jest --onlyChanged + +# Run tests related to specific files +jest --findRelatedTests src/utils.js src/components/Button.js + +# Run tests matching a name pattern +jest --testNamePattern="should render correctly" + +# List all tests Jest would run without executing them +jest --listTests + +# Run tests by exact file paths instead of patterns +jest --runTestsByPath +``` + +### Test Execution Control + +```bash +# Stop after N test failures +jest --bail +jest --bail=3 + +# Run tests serially in the current process +jest --runInBand + +# Set maximum number of worker processes +jest --maxWorkers=4 +jest --maxWorkers=50% + +# Set default timeout for tests +jest --testTimeout=10000 + +# Don't fail when no tests are found +jest --passWithNoTests +``` + +## Coverage Options + +### Basic Coverage + +```bash +# Collect and report test coverage +jest --coverage +jest --collectCoverage # equivalent + +# Specify coverage output directory +jest --coverageDirectory=coverage-report + +# Choose coverage provider +jest --coverageProvider=babel +jest --coverageProvider=v8 +``` + +### Coverage Configuration + +```bash +# Collect coverage from specific files +jest --collectCoverageFrom="src/**/*.js" --collectCoverageFrom="!src/**/*.test.js" + +# Ignore patterns for coverage +jest --coveragePathIgnorePatterns=node_modules --coveragePathIgnorePatterns=build + +# Specify coverage reporters +jest --coverageReporters=text --coverageReporters=html --coverageReporters=lcov + +# Set coverage thresholds (will fail if not met) +jest --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}' +``` + +## Output and Reporting + +### Output Formats + +```bash +# Output results in JSON format +jest --json + +# Write JSON output to a file +jest --json --outputFile=test-results.json + +# Verbose output showing individual test results +jest --verbose + +# Silent mode - prevent tests from printing to console +jest --silent + +# Disable stack traces in test output +jest --noStackTrace + +# Force colored output +jest --colors +``` + +### Advanced Output Control + +```bash +# Log heap usage after each test +jest --logHeapUsage + +# Detect and report memory leaks (experimental) +jest --detectLeaks + +# Detect handles that prevent Jest from exiting +jest --detectOpenHandles + +# Force Jest to exit after tests complete +jest --forceExit +``` + +## Configuration Options + +### Configuration Sources + +```bash +# Use specific config file +jest --config=jest.config.js +jest --config=package.json + +# Provide configuration as JSON string +jest --config='{"testEnvironment":"node"}' + +# Set root directory +jest --rootDir=/path/to/project + +# Specify multiple root directories +jest --roots=src --roots=lib + +# Run tests for multiple projects +jest --projects=project1 --projects=project2 +``` + +### Environment and Setup + +```bash +# Specify test environment +jest --testEnvironment=node +jest --testEnvironment=jsdom + +# Clear all mocks before each test +jest --clearMocks + +# Reset module registry before each test +jest --resetModules + +# Restore mocks after each test +jest --restoreMocks +``` + +## Cache Management + +```bash +# Use the transform cache (default: true) +jest --cache + +# Disable the transform cache +jest --no-cache + +# Specify cache directory +jest --cacheDirectory=/tmp/jest-cache + +# Clear cache and exit (useful for CI) +jest --clearCache +``` + +## Advanced Options + +### Development and Debugging + +```bash +# Enable debug mode +jest --debug + +# Throw error on deprecated API usage +jest --errorOnDeprecated + +# Update snapshots +jest --updateSnapshot + +# Randomize test order within files +jest --randomize + +# Set seed for test randomization +jest --seed=12345 +``` + +### Performance and Concurrency + +```bash +# Set maximum concurrent tests when using test.concurrent +jest --maxConcurrency=5 + +# Use specific number of workers +jest --maxWorkers=2 + +# Run tests in band (single process) for debugging +jest -i # short for --runInBand +``` + +## Watch Mode Patterns + +When running in watch mode (`--watch` or `--watchAll`), Jest provides an interactive interface: + +```bash +# Watch mode commands (available during watch mode): +# Press 'a' to run all tests +# Press 'f' to run only failed tests +# Press 'o' to only run tests related to changed files +# Press 'p' to filter by a filename regex pattern +# Press 't' to filter by a test name regex pattern +# Press 'q' to quit watch mode +# Press 'Enter' to trigger a test run +``` + +### Watch Mode Configuration + +```bash +# Ignore patterns in watch mode +jest --watch --watchPathIgnorePatterns=node_modules --watchPathIgnorePatterns=build + +# Watch all files (not just tracked by git) +jest --watchAll + +# Combine with other options +jest --watch --coverage --verbose +``` + +## CLI Argument Building Programmatically + +```typescript { .api } +import { buildArgv } from 'jest'; + +function buildArgv(maybeArgv?: Array): Promise +``` + +You can build CLI arguments programmatically using the `buildArgv` function: + +```typescript +import { buildArgv, runCLI } from 'jest'; + +// Build arguments for CI environment +const ciArgv = await buildArgv([ + '--ci', + '--coverage', + '--json', + '--runInBand', + '--passWithNoTests', + '--outputFile=test-results.json' +]); + +// Build arguments for development +const devArgv = await buildArgv([ + '--watch', + '--verbose', + '--testPathPatterns=src/' +]); + +// Build arguments with coverage thresholds +const strictArgv = await buildArgv([ + '--coverage', + '--coverageThreshold={"global":{"branches":90,"functions":90,"lines":90,"statements":90}}' +]); +``` + +## Common CLI Workflows + +### Continuous Integration + +```bash +# Typical CI command +jest --ci --coverage --json --runInBand --passWithNoTests --outputFile=results.json + +# With coverage enforcement +jest --ci --coverage --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}' +``` + +### Development Workflow + +```bash +# Start development with watch mode +jest --watch --verbose + +# Run tests for specific feature +jest --watch --testPathPatterns=src/features/auth + +# Debug failing tests +jest --runInBand --verbose --testNamePattern="failing test name" +``` + +### Pre-commit Checks + +```bash +# Run only tests related to staged files +jest --onlyChanged --passWithNoTests + +# Full validation with coverage +jest --coverage --bail=1 +``` + +### Performance Analysis + +```bash +# Analyze test performance +jest --verbose --logHeapUsage --detectLeaks + +# Profile with single worker for consistency +jest --runInBand --logHeapUsage +``` + +The Jest CLI provides comprehensive control over test execution, making it suitable for development, continuous integration, and automated testing workflows. \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/configuration.md b/.tessl/tiles/tessl/npm-jest/docs/configuration.md new file mode 100644 index 000000000..afd2b6e39 --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/configuration.md @@ -0,0 +1,513 @@ +# Configuration + +Jest provides a comprehensive configuration system supporting global settings, per-project configuration, and extensive customization options for all aspects of test execution. + +## Capabilities + +### Core Configuration Types + +Jest uses a hierarchical configuration system with different types serving specific purposes. + +```typescript { .api } +/** + * Main user configuration interface (alias for Config.InitialOptions) + * This is what users provide in jest.config.js or package.json + */ +interface Config { + // Test discovery + testMatch?: Array; + testRegex?: string | Array; + testPathIgnorePatterns?: Array; + + // Test environment + testEnvironment?: string; + testEnvironmentOptions?: Record; + + // Module resolution + moduleDirectories?: Array; + moduleFileExtensions?: Array; + moduleNameMapper?: Record; + modulePaths?: Array; + + // Transforms + transform?: Record; + transformIgnorePatterns?: Array; + + // Setup + setupFiles?: Array; + setupFilesAfterEnv?: Array; + + // Coverage + collectCoverage?: boolean; + collectCoverageFrom?: Array; + coverageDirectory?: string; + coveragePathIgnorePatterns?: Array; + coverageProvider?: "babel" | "v8"; + coverageReporters?: Array; + coverageThreshold?: Record>; + + // Execution + maxWorkers?: number | string; + testTimeout?: number; + + // Output + verbose?: boolean; + silent?: boolean; + + // Project structure + rootDir?: string; + roots?: Array; + projects?: Array; +} + +/** + * Global configuration that applies to the entire Jest run + */ +interface Config.GlobalConfig { + bail: number; + changedFilesWithAncestor: boolean; + changedSince?: string; + ci: boolean; + collectCoverage: boolean; + collectCoverageFrom: Array; + collectCoverageOnlyFrom?: Record; + coverageDirectory: string; + coveragePathIgnorePatterns?: Array; + coverageProvider: "babel" | "v8"; + coverageReporters: Array; + coverageThreshold?: Record>; + detectLeaks: boolean; + detectOpenHandles: boolean; + errorOnDeprecated: boolean; + expand: boolean; + filter?: string; + findRelatedTests: boolean; + forceExit: boolean; + json: boolean; + globalSetup?: string; + globalTeardown?: string; + lastCommit: boolean; + listTests: boolean; + logHeapUsage: boolean; + maxConcurrency: number; + maxWorkers: number; + noSCM?: boolean; + noStackTrace: boolean; + notify: boolean; + notifyMode: string; + onlyChanged: boolean; + onlyFailures: boolean; + outputFile?: string; + passWithNoTests: boolean; + projects: Array; + randomize?: boolean; + rootDir: string; + runTestsByPath: boolean; + seed?: number; + silent: boolean; + skipFilter: boolean; + testFailureExitCode: number; + testNamePattern?: string; + testPathPattern: string; + testPathPatterns: Array; + testResultsProcessor?: string; + testSequencer: string; + testTimeout?: number; + updateSnapshot: SnapshotUpdateState; + useStderr: boolean; + verbose?: boolean; + watch: boolean; + watchAll: boolean; + watchPathIgnorePatterns: Array; + watchman: boolean; +} + +/** + * Per-project configuration + */ +interface Config.ProjectConfig { + automock: boolean; + cache: boolean; + cacheDirectory: string; + clearMocks: boolean; + collectCoverageFrom: Array; + coveragePathIgnorePatterns: Array; + cwd: string; + dependencyExtractor?: string; + detectLeaks: boolean; + displayName?: string; + errorOnDeprecated: boolean; + extensionsToTreatAsEsm: Array; + extraGlobals: Array; + forceCoverageMatch: Array; + globalSetup?: string; + globalTeardown?: string; + globals: Record; + haste: HasteConfig; + injectGlobals: boolean; + moduleDirectories: Array; + moduleFileExtensions: Array; + moduleNameMapper: Array<[string, string]>; + modulePaths?: Array; + modulePathIgnorePatterns: Array; + preset?: string; + prettierPath: string; + resetMocks: boolean; + resetModules: boolean; + resolver?: string; + restoreMocks: boolean; + rootDir: string; + roots: Array; + runner: string; + setupFiles: Array; + setupFilesAfterEnv: Array; + skipFilter: boolean; + skipNodeResolution?: boolean; + slowTestThreshold: number; + snapshotResolver?: string; + snapshotSerializers: Array; + testEnvironment: string; + testEnvironmentOptions: Record; + testLocationInResults: boolean; + testMatch: Array; + testPathIgnorePatterns: Array; + testRegex: Array; + testRunner: string; + testURL?: string; + timers: "real" | "fake"; + transform: Array<[string, string, Record]>; + transformIgnorePatterns: Array; + unmockedModulePathPatterns?: Array; + watchPathIgnorePatterns: Array; +} + +/** + * Command line arguments interface + */ +interface Config.Argv { + // Test execution + all?: boolean; + bail?: boolean | number; + ci?: boolean; + findRelatedTests?: boolean; + listTests?: boolean; + onlyChanged?: boolean; + onlyFailures?: boolean; + passWithNoTests?: boolean; + runInBand?: boolean; + runTestsByPath?: boolean; + testNamePattern?: string; + testPathPatterns?: Array; + testTimeout?: number; + + // Watch mode + watch?: boolean; + watchAll?: boolean; + watchPathIgnorePatterns?: Array; + + // Coverage + collectCoverage?: boolean; + coverage?: boolean; + collectCoverageFrom?: Array; + coverageDirectory?: string; + coveragePathIgnorePatterns?: Array; + coverageProvider?: "babel" | "v8"; + coverageReporters?: Array; + coverageThreshold?: Record; + + // Output + json?: boolean; + outputFile?: string; + verbose?: boolean; + silent?: boolean; + noStackTrace?: boolean; + color?: boolean; + colors?: boolean; + + // Configuration + config?: string; + rootDir?: string; + roots?: Array; + projects?: Array; + maxWorkers?: number | string; + cache?: boolean; + clearCache?: boolean; + debug?: boolean; + updateSnapshot?: boolean; +} +``` + +### Configuration File Examples + +**Basic Configuration (jest.config.js):** + +```javascript +module.exports = { + // Test discovery + testMatch: ["**/__tests__/**/*.js", "**/?(*.)+(spec|test).js"], + testPathIgnorePatterns: ["/node_modules/", "/build/"], + + // Test environment + testEnvironment: "jsdom", + + // Module resolution + moduleDirectories: ["node_modules", "src"], + moduleFileExtensions: ["js", "json", "jsx", "ts", "tsx"], + moduleNameMapper: { + "^@/(.*)$": "/src/$1", + "\\.(css|less|scss)$": "identity-obj-proxy" + }, + + // Transforms + transform: { + "^.+\\.jsx?$": "babel-jest", + "^.+\\.tsx?$": "ts-jest" + }, + + // Setup + setupFilesAfterEnv: ["/src/setupTests.js"], + + // Coverage + collectCoverage: true, + collectCoverageFrom: [ + "src/**/*.{js,jsx,ts,tsx}", + "!src/**/*.d.ts", + "!src/index.js" + ], + coverageDirectory: "coverage", + coverageReporters: ["text", "lcov", "html"], + coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: 80 + } + } +}; +``` + +**TypeScript Configuration:** + +```javascript +module.exports = { + preset: "ts-jest", + testEnvironment: "node", + + // TypeScript specific + globals: { + "ts-jest": { + tsconfig: "tsconfig.test.json" + } + }, + + // Module resolution for TypeScript + moduleNameMapper: { + "^@/(.*)$": "/src/$1" + }, + + // File extensions + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json"], + + // Transform configuration + transform: { + "^.+\\.tsx?$": "ts-jest" + }, + + // Test files + testMatch: ["**/__tests__/**/*.ts", "**/?(*.)+(spec|test).ts"] +}; +``` + +**Multi-Project Configuration:** + +```javascript +module.exports = { + projects: [ + { + displayName: "client", + testMatch: ["/packages/client/**/*.test.js"], + testEnvironment: "jsdom", + setupFilesAfterEnv: ["/packages/client/src/setupTests.js"] + }, + { + displayName: "server", + testMatch: ["/packages/server/**/*.test.js"], + testEnvironment: "node", + setupFilesAfterEnv: ["/packages/server/src/setupTests.js"] + }, + { + displayName: "shared", + testMatch: ["/packages/shared/**/*.test.js"], + testEnvironment: "node" + } + ], + + // Global coverage settings + collectCoverage: true, + coverageDirectory: "coverage", + coverageReporters: ["text-summary", "html"] +}; +``` + +### Configuration Loading and Resolution + +Jest resolves configuration in the following order: + +1. `--config` CLI argument +2. `jest.config.js` file +3. `jest.config.ts` file +4. `jest` field in `package.json` +5. Default configuration + +**Programmatic Configuration:** + +```typescript +import { runCLI, buildArgv } from "jest"; + +// Override configuration programmatically +async function runWithCustomConfig() { + const customConfig = { + testMatch: ["**/*.custom.test.js"], + testEnvironment: "node", + collectCoverage: true + }; + + const argv = await buildArgv([ + `--config=${JSON.stringify(customConfig)}` + ]); + + return runCLI(argv, [process.cwd()]); +} + +// Merge with existing configuration +async function extendConfiguration(baseConfigPath: string) { + const baseConfig = require(baseConfigPath); + + const extendedConfig = { + ...baseConfig, + collectCoverage: true, + coverageThreshold: { + global: { + branches: 90, + functions: 90, + lines: 90, + statements: 90 + } + } + }; + + const argv = await buildArgv([ + `--config=${JSON.stringify(extendedConfig)}` + ]); + + return runCLI(argv, [process.cwd()]); +} +``` + +### Environment-Specific Configuration + +**Development Configuration:** + +```javascript +// jest.dev.config.js +module.exports = { + ...require('./jest.config.js'), + + // Development specific settings + verbose: true, + collectCoverage: false, + watchAll: true, + + // Faster transforms for development + transform: { + "^.+\\.jsx?$": "babel-jest" + } +}; +``` + +**CI Configuration:** + +```javascript +// jest.ci.config.js +module.exports = { + ...require('./jest.config.js'), + + // CI specific settings + ci: true, + collectCoverage: true, + coverageReporters: ["text", "lcov"], + maxWorkers: "50%", + cache: false, + + // Strict coverage requirements + coverageThreshold: { + global: { + branches: 90, + functions: 90, + lines: 90, + statements: 90 + } + } +}; +``` + +### Advanced Configuration Patterns + +**Dynamic Configuration:** + +```javascript +// jest.config.js +const isCI = process.env.CI === "true"; +const isDevelopment = process.env.NODE_ENV === "development"; + +module.exports = { + testMatch: ["**/__tests__/**/*.js", "**/?(*.)+(spec|test).js"], + + // Dynamic coverage settings + collectCoverage: isCI, + coverageReporters: isCI + ? ["text", "lcov"] + : ["text-summary"], + + // Dynamic worker settings + maxWorkers: isCI ? "50%" : 1, + + // Development specific settings + verbose: isDevelopment, + silent: isCI, + + // Environment specific transforms + transform: isDevelopment + ? { "^.+\\.jsx?$": "babel-jest" } + : { "^.+\\.jsx?$": ["babel-jest", { cacheDirectory: false }] } +}; +``` + +**Conditional Test Patterns:** + +```javascript +module.exports = { + // Base test patterns + testMatch: ["**/__tests__/**/*.js"], + + // Add integration tests in CI + ...(process.env.CI && { + testMatch: [ + "**/__tests__/**/*.js", + "**/integration/**/*.test.js" + ] + }), + + // Add e2e tests for full test runs + ...(process.env.FULL_TEST_SUITE && { + testMatch: [ + "**/__tests__/**/*.js", + "**/integration/**/*.test.js", + "**/e2e/**/*.test.js" + ] + }) +}; +``` + +Jest's configuration system provides complete control over test execution behavior, enabling optimization for different environments and use cases while maintaining consistency across development workflows. \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/index.md b/.tessl/tiles/tessl/npm-jest/docs/index.md new file mode 100644 index 000000000..2a5d4d660 --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/index.md @@ -0,0 +1,212 @@ +# Jest + +Jest is a comprehensive JavaScript testing framework designed for delightful testing experiences. It provides a complete testing solution that works out of the box for most JavaScript projects, featuring instant feedback through intelligent watch mode, powerful snapshot testing, extensive mocking capabilities, built-in code coverage reporting, and seamless integration with modern JavaScript tooling including Babel, TypeScript, webpack, and various bundlers. + +## Package Information + +- **Package Name**: jest +- **Package Type**: npm +- **Language**: TypeScript/JavaScript +- **Installation**: `npm install jest` + +## Core Imports + +```typescript +import { runCLI, createTestScheduler, SearchSource, getVersion, run, buildArgv } from "jest"; +import type { Config } from "jest"; +``` + +For CommonJS: + +```javascript +const { runCLI, createTestScheduler, SearchSource, getVersion, run, buildArgv } = require("jest"); +``` + +## Basic Usage + +Jest can be used programmatically or via CLI: + +```typescript +import { runCLI } from "jest"; + +// Run Jest programmatically +const { results, globalConfig } = await runCLI( + { roots: ["/src"], testMatch: ["**/__tests__/**/*.test.js"] }, + ["./src"] +); + +console.log(`Tests completed: ${results.numTotalTests}`); +console.log(`Tests passed: ${results.numPassedTests}`); +``` + +CLI usage: + +```bash +# Run all tests +jest + +# Run tests in watch mode +jest --watch + +# Run with coverage +jest --coverage + +# Run specific test files +jest user.test.js +``` + +## Architecture + +Jest is built around several key components: + +- **Test Runner**: Core engine that discovers, schedules, and executes tests +- **CLI Interface**: Command-line interface for running tests with extensive options +- **SearchSource**: Test file discovery and filtering system +- **TestScheduler**: Test execution scheduling and reporter management +- **Configuration System**: Flexible configuration for projects and global settings +- **Reporter System**: Extensible test result reporting and output formatting + +## Capabilities + +### Test Running and Execution + +Core test running functionality including programmatic API and CLI runner with comprehensive test discovery and execution capabilities. + +```typescript { .api } +function runCLI( + argv: Config.Argv, + projects: Array +): Promise<{ + results: AggregatedResult; + globalConfig: Config.GlobalConfig; +}>; + +function run(maybeArgv?: Array, project?: string): Promise; +``` + +[Test Runner](./test-runner.md) + +### CLI Usage and Options + +Command-line interface providing over 70 options for test execution, coverage collection, watch mode, output formatting, and project configuration. + +```typescript { .api } +function buildArgv(maybeArgv?: Array): Promise; +``` + +[CLI Usage](./cli-usage.md) + +### Test Discovery and Search + +Advanced test file discovery system with pattern matching, dependency tracking, and change detection for optimized test runs. + +```typescript { .api } +class SearchSource { + constructor(context: TestContext); + isTestFilePath(path: string): boolean; + findMatchingTests(testPathPatternsExecutor: TestPathPatternsExecutor): SearchResult; + findTestsByPaths(paths: Array): SearchResult; + findRelatedTests(allPaths: Set, collectCoverage: boolean): Promise; +} +``` + +[Test Discovery](./test-discovery.md) + +### Configuration Management + +Comprehensive configuration system supporting global settings, per-project configuration, and extensive customization options for all aspects of test execution. + +```typescript { .api } +interface Config { + // Main configuration interface (alias for Config.InitialOptions) + testEnvironment?: string; + testMatch?: Array; + transform?: Record; + setupFilesAfterEnv?: Array; + moduleNameMapping?: Record; + collectCoverage?: boolean; +} + +interface Config.GlobalConfig { + bail: number; + collectCoverage: boolean; + maxWorkers: number; + rootDir: string; + watch: boolean; + watchAll: boolean; +} +``` + +[Configuration](./configuration.md) + +### Test Scheduling and Reporting + +Test execution scheduling with multi-process coordination, reporter management, and comprehensive result aggregation. + +```typescript { .api } +function createTestScheduler( + globalConfig: Config.GlobalConfig, + context: TestSchedulerContext +): Promise; + +class TestScheduler { + constructor(globalConfig: Config.GlobalConfig, context: TestSchedulerContext); + addReporter(reporter: Reporter): void; + scheduleTests(tests: Array, watcher: TestWatcher): Promise; +} +``` + +[Test Scheduling](./test-scheduling.md) + +## Utility Functions + +```typescript { .api } +function getVersion(): string; +``` + +Returns the current Jest version. + +## Core Types + +```typescript { .api } +interface AggregatedResult { + numTotalTests: number; + numPassedTests: number; + numFailedTests: number; + numPendingTests: number; + numRuntimeErrorTestSuites: number; + numTotalTestSuites: number; + numPassedTestSuites: number; + numFailedTestSuites: number; + numPendingTestSuites: number; + openHandles: Array; + snapshot: SnapshotSummary; + success: boolean; + startTime: number; + testResults: Array; + wasInterrupted: boolean; +} + +interface SearchResult { + noSCM?: boolean; + stats?: Stats; + collectCoverageFrom?: Set; + tests: Array; + total?: number; +} + +interface TestContext { + config: Config.ProjectConfig; + hasteFS: IHasteFS; + moduleMap: IModuleMap; + resolver: IResolver; +} + +interface TestSchedulerContext extends ReporterContext, TestRunnerContext {} + +interface Test { + context: TestContext; + duration?: number; + path: string; +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/test-discovery.md b/.tessl/tiles/tessl/npm-jest/docs/test-discovery.md new file mode 100644 index 000000000..43d1d2af8 --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/test-discovery.md @@ -0,0 +1,307 @@ +# Test Discovery + +Jest's test discovery system provides advanced capabilities for finding, filtering, and organizing test files with pattern matching, dependency tracking, and change detection for optimized test runs. + +## Capabilities + +### SearchSource Class + +The SearchSource class is the core component responsible for test file discovery and filtering. + +```typescript { .api } +/** + * Core class for finding and filtering test files + */ +class SearchSource { + constructor(context: TestContext); + + /** + * Determines if a given path is a test file based on configuration + * @param path - File path to check + * @returns True if the path matches test file patterns + */ + isTestFilePath(path: string): boolean; + + /** + * Finds tests matching the given path patterns + * @param testPathPatternsExecutor - Pattern executor for test paths + * @returns Search results with matching tests + */ + findMatchingTests(testPathPatternsExecutor: TestPathPatternsExecutor): SearchResult; + + /** + * Finds tests by exact file paths + * @param paths - Array of exact file paths + * @returns Search results with specified test files + */ + findTestsByPaths(paths: Array): SearchResult; + + /** + * Finds tests related to the given source file paths + * @param allPaths - Set of source file paths + * @param collectCoverage - Whether to collect coverage information + * @returns Promise resolving to search results with related tests + */ + findRelatedTests(allPaths: Set, collectCoverage: boolean): Promise; + + /** + * Main method to get test paths based on configuration and options + * @param globalConfig - Global Jest configuration + * @param projectConfig - Project-specific configuration + * @param changedFiles - Optional changed files information + * @param filter - Optional filter function + * @returns Promise resolving to comprehensive search results + */ + getTestPaths( + globalConfig: Config.GlobalConfig, + projectConfig: Config.ProjectConfig, + changedFiles?: ChangedFiles, + filter?: Filter + ): Promise; +} + +interface SearchResult { + noSCM?: boolean; + stats?: Stats; + collectCoverageFrom?: Set; + tests: Array; + total?: number; +} + +interface Stats { + roots: number; + testMatch: number; + testPathIgnorePatterns: number; + testRegex: number; + testPathPatterns?: number; +} +``` + +**Usage Examples:** + +```typescript +import { SearchSource } from "jest"; + +// Create SearchSource instance +const searchSource = new SearchSource(testContext); + +// Find all test files +const allTests = await searchSource.getTestPaths( + globalConfig, + projectConfig +); + +console.log(`Found ${allTests.tests.length} test files`); + +// Check if a file is a test file +const isTest = searchSource.isTestFilePath("src/__tests__/utils.test.js"); +console.log(`Is test file: ${isTest}`); + +// Find tests related to changed source files +const changedFiles = new Set(["src/utils.js", "src/components/Button.js"]); +const relatedTests = await searchSource.findRelatedTests(changedFiles, false); + +console.log(`Found ${relatedTests.tests.length} related tests`); +``` + +### Test Pattern Matching + +Advanced pattern matching for test file discovery: + +```typescript +// Find tests by exact paths +const specificTests = searchSource.findTestsByPaths([ + "src/components/Button.test.js", + "src/utils/helpers.test.js" +]); + +// Find tests matching patterns (via getTestPaths) +const patternTests = await searchSource.getTestPaths( + { + ...globalConfig, + testPathPatterns: ["components", "utils"] + }, + projectConfig +); +``` + +### Change Detection Integration + +Optimize test runs by finding tests related to changed files: + +```typescript +import { SearchSource } from "jest"; + +async function runTestsForChangedFiles( + searchSource: SearchSource, + changedFiles: string[] +) { + // Find tests related to changed source files + const relatedTests = await searchSource.findRelatedTests( + new Set(changedFiles), + true // collectCoverage + ); + + if (relatedTests.tests.length === 0) { + console.log("No tests found for changed files"); + return null; + } + + return relatedTests; +} + +// Usage with git integration +async function findTestsForGitChanges() { + const changedFiles = await getChangedFilesFromGit(); + const relatedTests = await searchSource.findRelatedTests( + new Set(changedFiles), + false + ); + + return relatedTests.tests.map(test => test.path); +} +``` + +### Custom Test Discovery Patterns + +Implement custom test discovery logic: + +```typescript +import { SearchSource } from "jest"; + +class CustomTestDiscovery { + constructor(private searchSource: SearchSource) {} + + async findTestsByFeature(featureName: string) { + // Find all tests + const allTests = await this.searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + // Filter by feature directory or naming convention + const featureTests = allTests.tests.filter(test => + test.path.includes(`features/${featureName}`) || + test.path.includes(`${featureName}.test.`) + ); + + return { + ...allTests, + tests: featureTests, + total: featureTests.length + }; + } + + async findTestsByTags(tags: string[]) { + const allTests = await this.searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + // Filter tests based on file content or naming patterns + const taggedTests = allTests.tests.filter(test => { + const filename = test.path.toLowerCase(); + return tags.some(tag => filename.includes(tag.toLowerCase())); + }); + + return { + ...allTests, + tests: taggedTests, + total: taggedTests.length + }; + } + + async findSlowTests(thresholdMs: number = 1000) { + // This would typically require historical test timing data + // Implementation would depend on custom test result storage + const allTests = await this.searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + // Example: identify tests by naming convention + const potentiallySlowTests = allTests.tests.filter(test => + test.path.includes("integration") || + test.path.includes("e2e") || + test.path.includes("slow") + ); + + return { + ...allTests, + tests: potentiallySlowTests, + total: potentiallySlowTests.length + }; + } +} +``` + +### Performance Optimization + +Optimize test discovery for large codebases: + +```typescript +async function optimizedTestDiscovery( + searchSource: SearchSource, + options: { + useCache?: boolean; + maxFiles?: number; + changedFilesOnly?: boolean; + } = {} +) { + if (options.changedFilesOnly) { + // Only find tests related to changed files + const changedFiles = await getChangedFiles(); + return searchSource.findRelatedTests(new Set(changedFiles), false); + } + + // Get all tests with potential limits + const allTests = await searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + if (options.maxFiles && allTests.tests.length > options.maxFiles) { + // Limit test count for performance + const limitedTests = allTests.tests.slice(0, options.maxFiles); + console.warn(`Limited to ${options.maxFiles} tests (found ${allTests.tests.length})`); + + return { + ...allTests, + tests: limitedTests, + total: limitedTests.length + }; + } + + return allTests; +} +``` + +## Integration with Test Execution + +The SearchSource integrates seamlessly with Jest's test execution pipeline: + +```typescript +import { SearchSource, createTestScheduler } from "jest"; + +async function discoverAndRunTests() { + // 1. Discover tests + const searchSource = new SearchSource(testContext); + const searchResult = await searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + // 2. Create scheduler + const scheduler = await createTestScheduler(globalConfig, schedulerContext); + + // 3. Execute discovered tests + const results = await scheduler.scheduleTests( + searchResult.tests, + testWatcher + ); + + return results; +} +``` + +Jest's test discovery system provides the foundation for intelligent test execution, enabling optimized test runs based on code changes, file patterns, and custom discovery logic. \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/test-runner.md b/.tessl/tiles/tessl/npm-jest/docs/test-runner.md new file mode 100644 index 000000000..b9f918078 --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/test-runner.md @@ -0,0 +1,280 @@ +# Test Runner + +Jest's test runner provides both programmatic and CLI-based test execution with comprehensive configuration options, result aggregation, and performance optimization through parallel execution. + +## Capabilities + +### Programmatic Test Execution + +Run Jest tests programmatically with full control over configuration and execution parameters. + +```typescript { .api } +/** + * Runs Jest CLI programmatically with specified configuration and projects + * @param argv - Command line arguments and configuration + * @param projects - Array of project paths to run tests on + * @returns Promise resolving to test results and global configuration + */ +function runCLI( + argv: Config.Argv, + projects: Array +): Promise<{ + results: AggregatedResult; + globalConfig: Config.GlobalConfig; +}>; + +interface AggregatedResult { + numTotalTests: number; + numPassedTests: number; + numFailedTests: number; + numPendingTests: number; + numRuntimeErrorTestSuites: number; + numTotalTestSuites: number; + numPassedTestSuites: number; + numFailedTestSuites: number; + numPendingTestSuites: number; + openHandles: Array; + snapshot: SnapshotSummary; + success: boolean; + startTime: number; + testResults: Array; + wasInterrupted: boolean; +} +``` + +**Usage Examples:** + +```typescript +import { runCLI, buildArgv } from "jest"; + +// Basic test run +async function runTests() { + const argv = await buildArgv(["--testMatch=**/*.test.js"]); + const { results, globalConfig } = await runCLI(argv, ["./src"]); + + console.log(`${results.numPassedTests}/${results.numTotalTests} tests passed`); + + if (!results.success) { + console.error("Tests failed!"); + process.exit(1); + } +} + +// Run with coverage and JSON output +async function runTestsWithCoverage() { + const argv = await buildArgv([ + "--coverage", + "--json", + "--outputFile=test-results.json" + ]); + + const { results } = await runCLI(argv, [process.cwd()]); + return results; +} + +// Run specific test files +async function runSpecificTests(testFiles: string[]) { + const argv = await buildArgv([ + "--runTestsByPath", + ...testFiles + ]); + + const { results } = await runCLI(argv, [process.cwd()]); + return results; +} +``` + +### CLI Entry Point + +Main CLI runner that handles argument parsing and delegates to the programmatic API. + +```typescript { .api } +/** + * Main CLI entry point for Jest + * @param maybeArgv - Optional command line arguments (defaults to process.argv.slice(2)) + * @param project - Optional project path + * @returns Promise that resolves when Jest execution completes + */ +function run(maybeArgv?: Array, project?: string): Promise; +``` + +**Usage Example:** + +```typescript +import { run } from "jest"; + +// Run Jest with default arguments +await run(); + +// Run Jest with custom arguments +await run(["--watch", "--testPathPatterns=src/components"]); + +// Run Jest for specific project +await run(["--coverage"], "./my-project"); +``` + +### Argument Parsing and Validation + +Parse and validate command line arguments for Jest execution. + +```typescript { .api } +/** + * Builds and validates command line arguments for Jest + * @param maybeArgv - Optional command line arguments + * @returns Promise resolving to parsed and validated arguments + */ +function buildArgv(maybeArgv?: Array): Promise; + +interface Config.Argv { + // Test execution options + all?: boolean; + bail?: boolean | number; + findRelatedTests?: boolean; + listTests?: boolean; + onlyChanged?: boolean; + onlyFailures?: boolean; + passWithNoTests?: boolean; + runInBand?: boolean; + runTestsByPath?: boolean; + testNamePattern?: string; + testPathPatterns?: Array; + testTimeout?: number; + + // Watch mode options + watch?: boolean; + watchAll?: boolean; + watchPathIgnorePatterns?: Array; + + // Coverage options + collectCoverage?: boolean; + coverage?: boolean; + collectCoverageFrom?: Array; + coverageDirectory?: string; + coveragePathIgnorePatterns?: Array; + coverageProvider?: "babel" | "v8"; + coverageReporters?: Array; + coverageThreshold?: Record; + + // Output options + json?: boolean; + outputFile?: string; + verbose?: boolean; + silent?: boolean; + noStackTrace?: boolean; + color?: boolean; + colors?: boolean; + + // Configuration options + config?: string; + rootDir?: string; + roots?: Array; + projects?: Array; + maxWorkers?: number | string; + cache?: boolean; + clearCache?: boolean; + debug?: boolean; + updateSnapshot?: boolean; +} +``` + +### Integration Patterns + +Common patterns for integrating Jest into build tools and custom workflows: + +**Build Tool Integration:** + +```typescript +import { runCLI, buildArgv } from "jest"; + +async function buildToolIntegration(options: { + testFiles?: string[]; + coverage?: boolean; + watch?: boolean; +}) { + const args = []; + + if (options.coverage) args.push("--coverage"); + if (options.watch) args.push("--watch"); + if (options.testFiles) { + args.push("--runTestsByPath", ...options.testFiles); + } + + const argv = await buildArgv(args); + const { results } = await runCLI(argv, [process.cwd()]); + + return { + success: results.success, + testCount: results.numTotalTests, + passedTests: results.numPassedTests, + failedTests: results.numFailedTests, + coverageMap: results.coverageMap + }; +} +``` + +**CI/CD Integration:** + +```typescript +import { runCLI, buildArgv } from "jest"; + +async function runTestsInCI() { + const argv = await buildArgv([ + "--ci", + "--coverage", + "--json", + "--outputFile=test-results.json", + "--coverageReporters=text-lcov", + "--coverageDirectory=coverage" + ]); + + try { + const { results, globalConfig } = await runCLI(argv, [process.cwd()]); + + // Log summary + console.log(`Tests: ${results.numPassedTests}/${results.numTotalTests} passed`); + console.log(`Test Suites: ${results.numPassedTestSuites}/${results.numTotalTestSuites} passed`); + + if (!results.success) { + console.error("❌ Tests failed"); + process.exit(1); + } + + console.log("✅ All tests passed"); + } catch (error) { + console.error("Error running tests:", error); + process.exit(1); + } +} +``` + +**Custom Test Discovery:** + +```typescript +import { runCLI, buildArgv } from "jest"; +import * as fs from "fs"; +import * as path from "path"; + +async function runTestsForChangedFiles(changedFiles: string[]) { + // Find test files related to changed source files + const testFiles = changedFiles + .filter(file => file.endsWith('.js') || file.endsWith('.ts')) + .map(file => { + const testFile = file.replace(/\.(js|ts)$/, '.test.$1'); + return fs.existsSync(testFile) ? testFile : null; + }) + .filter(Boolean) as string[]; + + if (testFiles.length === 0) { + console.log("No test files found for changed files"); + return; + } + + const argv = await buildArgv([ + "--runTestsByPath", + ...testFiles + ]); + + const { results } = await runCLI(argv, [process.cwd()]); + return results; +} +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/docs/test-scheduling.md b/.tessl/tiles/tessl/npm-jest/docs/test-scheduling.md new file mode 100644 index 000000000..33ad6d920 --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/docs/test-scheduling.md @@ -0,0 +1,501 @@ +# Test Scheduling + +Jest's test scheduling system manages test execution coordination, multi-process scheduling, reporter management, and comprehensive result aggregation for optimal performance and reporting. + +## Capabilities + +### TestScheduler Class + +The TestScheduler manages test execution scheduling and coordinates with reporters for comprehensive test result processing. + +```typescript { .api } +/** + * Manages test execution scheduling and reporting + */ +class TestScheduler { + constructor(globalConfig: Config.GlobalConfig, context: TestSchedulerContext); + + /** + * Adds a reporter to the dispatcher + * @param reporter - Reporter instance to add + */ + addReporter(reporter: Reporter): void; + + /** + * Removes a reporter from the dispatcher + * @param reporterConstructor - Constructor of reporter to remove + */ + removeReporter(reporterConstructor: ReporterConstructor): void; + + /** + * Schedules and executes the given tests + * @param tests - Array of test files to execute + * @param watcher - Test watcher for watch mode integration + * @returns Promise resolving to aggregated test results + */ + scheduleTests(tests: Array, watcher: TestWatcher): Promise; +} + +/** + * Factory function that creates a TestScheduler and sets up reporters + * @param globalConfig - Global Jest configuration + * @param context - Scheduler context including reporter and test runner contexts + * @returns Promise resolving to configured test scheduler + */ +function createTestScheduler( + globalConfig: Config.GlobalConfig, + context: TestSchedulerContext +): Promise; + +type TestSchedulerContext = ReporterContext & TestRunnerContext; + +type ReporterConstructor = new ( + globalConfig: Config.GlobalConfig, + reporterConfig: Record, + reporterContext: ReporterContext, +) => JestReporter; +``` + +**Usage Examples:** + +```typescript +import { createTestScheduler, SearchSource } from "jest"; + +// Create and configure test scheduler +async function setupTestScheduler() { + const scheduler = await createTestScheduler(globalConfig, { + ...reporterContext, + ...testRunnerContext + }); + + // Add custom reporter + scheduler.addReporter(new CustomReporter(globalConfig, {}, reporterContext)); + + return scheduler; +} + +// Execute tests with scheduler +async function executeTests(testFiles: Array) { + const scheduler = await setupTestScheduler(); + + const results = await scheduler.scheduleTests( + testFiles, + new TestWatcher({ isWatchMode: false }) + ); + + return results; +} +``` + +### Test Execution Coordination + +The TestScheduler coordinates test execution across multiple processes and manages the complete test lifecycle. + +**Basic Test Scheduling:** + +```typescript +import { createTestScheduler, SearchSource } from "jest"; + +async function coordinateTestExecution() { + // 1. Discover tests + const searchSource = new SearchSource(testContext); + const searchResult = await searchSource.getTestPaths( + globalConfig, + projectConfig + ); + + // 2. Create scheduler + const scheduler = await createTestScheduler(globalConfig, schedulerContext); + + // 3. Schedule and execute tests + const results = await scheduler.scheduleTests( + searchResult.tests, + new TestWatcher({ isWatchMode: false }) + ); + + console.log(`Executed ${results.numTotalTests} tests`); + console.log(`Passed: ${results.numPassedTests}`); + console.log(`Failed: ${results.numFailedTests}`); + + return results; +} +``` + +### Reporter Management + +Manage test result reporting through dynamic reporter configuration. + +```typescript +import { createTestScheduler } from "jest"; + +// Custom reporter for specialized output +class CustomReporter { + constructor( + private globalConfig: Config.GlobalConfig, + private options: Record, + private context: ReporterContext + ) {} + + onRunStart(results: AggregatedResult, options: ReporterOnStartOptions) { + console.log("Starting test run..."); + } + + onTestResult(test: Test, testResult: TestResult, results: AggregatedResult) { + if (testResult.testResults.some(result => result.status === "failed")) { + console.log(`❌ ${test.path}`); + } else { + console.log(`✅ ${test.path}`); + } + } + + onRunComplete(contexts: Set, results: AggregatedResult) { + console.log(`Test run completed: ${results.success ? "PASSED" : "FAILED"}`); + } +} + +// Configure scheduler with custom reporters +async function setupCustomReporting() { + const scheduler = await createTestScheduler(globalConfig, schedulerContext); + + // Add multiple reporters + scheduler.addReporter(new CustomReporter(globalConfig, {}, reporterContext)); + scheduler.addReporter(new JSONReporter(globalConfig, { outputFile: "results.json" }, reporterContext)); + + // Remove default reporter if needed + scheduler.removeReporter(DefaultReporter); + + return scheduler; +} +``` + +### Multi-Process Coordination + +Handle test execution across multiple worker processes for optimal performance. + +```typescript +import { createTestScheduler } from "jest"; + +async function scheduleTestsWithWorkers(maxWorkers: number) { + const globalConfig = { + ...baseGlobalConfig, + maxWorkers, + runInBand: maxWorkers === 1 + }; + + const scheduler = await createTestScheduler(globalConfig, schedulerContext); + + // Configure for multi-process execution + const results = await scheduler.scheduleTests( + testFiles, + new TestWatcher({ + isWatchMode: false, + // Additional options for worker coordination + }) + ); + + return results; +} + +// Adaptive worker configuration +async function adaptiveTestScheduling(testCount: number) { + // Determine optimal worker count based on test count and system resources + const maxWorkers = Math.min( + Math.max(1, Math.floor(testCount / 10)), // At least 10 tests per worker + require("os").cpus().length, // Don't exceed CPU count + 8 // Cap at 8 workers + ); + + return scheduleTestsWithWorkers(maxWorkers); +} +``` + +### Watch Mode Integration + +Integrate with Jest's watch mode for automatic test re-execution. + +```typescript +import { createTestScheduler } from "jest"; +import { TestWatcher } from "jest-watcher"; + +async function scheduleTestsInWatchMode() { + const scheduler = await createTestScheduler( + { ...globalConfig, watch: true }, + schedulerContext + ); + + const watcher = new TestWatcher({ isWatchMode: true }); + + // Watch mode provides automatic re-scheduling + const results = await scheduler.scheduleTests(testFiles, watcher); + + // In watch mode, this promise typically never resolves + // as Jest continues watching for file changes + return results; +} + +// Custom watch mode logic +class CustomTestWatcher extends TestWatcher { + constructor(options: { isWatchMode: boolean }) { + super(options); + } + + async onChange(changedFiles: Set) { + console.log(`Files changed: ${Array.from(changedFiles).join(", ")}`); + + // Custom logic for determining which tests to re-run + const searchSource = new SearchSource(testContext); + const relatedTests = await searchSource.findRelatedTests(changedFiles, false); + + // Re-schedule only related tests + if (relatedTests.tests.length > 0) { + await this.scheduler.scheduleTests(relatedTests.tests, this); + } + } +} +``` + +### Result Aggregation and Processing + +Process and aggregate test results for comprehensive reporting. + +```typescript +import { createTestScheduler } from "jest"; + +interface TestExecutionMetrics { + totalDuration: number; + averageTestDuration: number; + slowestTests: Array<{ path: string; duration: number }>; + fastestTests: Array<{ path: string; duration: number }>; + failureRate: number; + coveragePercentage?: number; +} + +async function executeWithMetrics(tests: Array): Promise<{ + results: AggregatedResult; + metrics: TestExecutionMetrics; +}> { + const scheduler = await createTestScheduler(globalConfig, schedulerContext); + + const startTime = Date.now(); + const results = await scheduler.scheduleTests( + tests, + new TestWatcher({ isWatchMode: false }) + ); + const totalDuration = Date.now() - startTime; + + // Calculate metrics + const testDurations = results.testResults + .flatMap(suite => suite.testResults) + .map(test => ({ path: test.title, duration: test.duration || 0 })) + .filter(test => test.duration > 0); + + const averageTestDuration = testDurations.length > 0 + ? testDurations.reduce((sum, test) => sum + test.duration, 0) / testDurations.length + : 0; + + const sortedByDuration = testDurations.sort((a, b) => b.duration - a.duration); + + const metrics: TestExecutionMetrics = { + totalDuration, + averageTestDuration, + slowestTests: sortedByDuration.slice(0, 5), + fastestTests: sortedByDuration.slice(-5).reverse(), + failureRate: results.numTotalTests > 0 + ? results.numFailedTests / results.numTotalTests + : 0, + coveragePercentage: results.coverageMap + ? calculateCoveragePercentage(results.coverageMap) + : undefined + }; + + return { results, metrics }; +} + +function calculateCoveragePercentage(coverageMap: any): number { + // Implementation would depend on coverage map structure + // This is a simplified example + const summary = coverageMap.getCoverageSummary?.(); + return summary?.lines?.pct || 0; +} +``` + +### Error Handling and Recovery + +Implement robust error handling for test scheduling failures. + +```typescript +import { createTestScheduler } from "jest"; + +async function robustTestScheduling(tests: Array) { + let scheduler: TestScheduler; + + try { + scheduler = await createTestScheduler(globalConfig, schedulerContext); + } catch (error) { + console.error("Failed to create test scheduler:", error); + throw new Error("Test scheduler initialization failed"); + } + + // Add error reporter + scheduler.addReporter(new ErrorTrackingReporter()); + + try { + const results = await scheduler.scheduleTests( + tests, + new TestWatcher({ isWatchMode: false }) + ); + + // Check for critical failures + if (results.numRuntimeErrorTestSuites > 0) { + console.warn(`${results.numRuntimeErrorTestSuites} test suites had runtime errors`); + } + + // Handle open handles + if (results.openHandles && results.openHandles.length > 0) { + console.warn(`${results.openHandles.length} open handles detected`); + + // Optionally force exit + if (globalConfig.forceExit) { + process.exit(results.success ? 0 : 1); + } + } + + return results; + + } catch (error) { + console.error("Test execution failed:", error); + + // Attempt recovery or cleanup + if (error.message.includes("worker")) { + console.log("Retrying with single worker..."); + const fallbackConfig = { ...globalConfig, maxWorkers: 1, runInBand: true }; + const fallbackScheduler = await createTestScheduler(fallbackConfig, schedulerContext); + return fallbackScheduler.scheduleTests(tests, new TestWatcher({ isWatchMode: false })); + } + + throw error; + } +} + +class ErrorTrackingReporter { + private errors: Array<{ test: string; error: any }> = []; + + onTestResult(test: Test, testResult: TestResult) { + testResult.testResults.forEach(result => { + if (result.status === "failed") { + this.errors.push({ + test: `${test.path} > ${result.title}`, + error: result.failureMessages + }); + } + }); + } + + onRunComplete() { + if (this.errors.length > 0) { + console.log("\n=== Test Failures Summary ==="); + this.errors.forEach(({ test, error }) => { + console.log(`\n❌ ${test}`); + console.log(error.join("\n")); + }); + } + } +} +``` + +### Performance Optimization + +Optimize test scheduling for different scenarios and constraints. + +```typescript +import { createTestScheduler } from "jest"; + +interface SchedulingStrategy { + name: string; + configure: (config: Config.GlobalConfig) => Config.GlobalConfig; +} + +const schedulingStrategies: Record = { + fast: { + name: "Fast Execution", + configure: (config) => ({ + ...config, + maxWorkers: "100%", + cache: true, + bail: 1 // Stop on first failure + }) + }, + + thorough: { + name: "Thorough Testing", + configure: (config) => ({ + ...config, + maxWorkers: "50%", + collectCoverage: true, + bail: false + }) + }, + + debug: { + name: "Debug Mode", + configure: (config) => ({ + ...config, + maxWorkers: 1, + runInBand: true, + verbose: true, + detectOpenHandles: true + }) + }, + + ci: { + name: "CI Optimized", + configure: (config) => ({ + ...config, + ci: true, + maxWorkers: "50%", + cache: false, + collectCoverage: true, + coverageReporters: ["text", "lcov"] + }) + } +}; + +async function scheduleWithStrategy( + tests: Array, + strategyName: keyof typeof schedulingStrategies +) { + const strategy = schedulingStrategies[strategyName]; + const optimizedConfig = strategy.configure(globalConfig); + + console.log(`Using ${strategy.name} strategy`); + + const scheduler = await createTestScheduler(optimizedConfig, schedulerContext); + return scheduler.scheduleTests( + tests, + new TestWatcher({ isWatchMode: false }) + ); +} + +// Auto-select strategy based on environment +async function smartScheduling(tests: Array) { + const isCI = process.env.CI === "true"; + const isDebug = process.env.DEBUG === "true"; + const testCount = tests.length; + + let strategy: keyof typeof schedulingStrategies; + + if (isDebug) { + strategy = "debug"; + } else if (isCI) { + strategy = "ci"; + } else if (testCount < 10) { + strategy = "fast"; + } else { + strategy = "thorough"; + } + + return scheduleWithStrategy(tests, strategy); +} +``` + +Jest's test scheduling system provides complete control over test execution coordination, enabling optimized performance, comprehensive reporting, and reliable test execution across different environments and use cases. \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-jest/tile.json b/.tessl/tiles/tessl/npm-jest/tile.json new file mode 100644 index 000000000..95fca495b --- /dev/null +++ b/.tessl/tiles/tessl/npm-jest/tile.json @@ -0,0 +1,7 @@ +{ + "name": "tessl/npm-jest", + "version": "30.1.0", + "docs": "docs/index.md", + "describes": "pkg:npm/jest@30.1.3", + "summary": "Delightful JavaScript testing framework with built-in test runner, assertion library, mocking, and coverage reporting." +} \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-mocha/docs/browser.md b/.tessl/tiles/tessl/npm-mocha/docs/browser.md new file mode 100644 index 000000000..ddc955e25 --- /dev/null +++ b/.tessl/tiles/tessl/npm-mocha/docs/browser.md @@ -0,0 +1,435 @@ +# Browser Support + +Browser-specific functionality for running Mocha tests in web browsers with DOM integration, process shims, and browser-optimized features. + +## Capabilities + +### Browser Setup + +Initialize Mocha for browser environments with configuration and DOM integration. + +```javascript { .api } +/** + * Browser-specific mocha setup function + * @param options - Browser configuration options + * @returns {mocha} Global mocha instance + */ +mocha.setup(options); + +/** + * Browser setup options + */ +interface BrowserSetupOptions { + ui?: string; // Interface: 'bdd', 'tdd', 'qunit', 'exports' + reporter?: string; // Reporter name (defaults to 'html') + timeout?: number; // Global timeout in milliseconds + slow?: number; // Slow test threshold + grep?: string; // Test filter pattern + fgrep?: string; // Fixed string filter + invert?: boolean; // Invert grep pattern + bail?: boolean; // Bail on first failure + checkLeaks?: boolean; // Check for global leaks + globals?: string[]; // Global variables to ignore + delay?: boolean; // Delay test execution + noHighlighting?: boolean; // Disable syntax highlighting +} +``` + +**Usage Examples:** + +```html + + + + Mocha Tests + + + +
+ + + + + + + + + + +``` + +```javascript +// String-based setup (shorthand for ui) +mocha.setup('bdd'); + +// Object-based setup with full options +mocha.setup({ + ui: 'tdd', + reporter: 'html', + timeout: 10000, + globals: ['MY_GLOBAL'] +}); +``` + +### Browser Test Execution + +Execute tests in browser environment with DOM integration and result display. + +```javascript { .api } +/** + * Run tests in browser environment + * @param callback - Optional completion callback + * @returns {Runner} Runner instance + */ +mocha.run(callback); + +/** + * Callback function signature + * @param failures - Number of failed tests + */ +type RunCallback = (failures: number) => void; +``` + +**Usage Examples:** + +```javascript +// Basic execution +mocha.run(); + +// With completion callback +mocha.run(function(failures) { + console.log('Tests completed'); + console.log(`Failed tests: ${failures}`); + + // Report results to parent window or test runner + if (window.parent !== window) { + window.parent.postMessage({ + type: 'test-results', + failures: failures + }, '*'); + } +}); + +// Get runner instance for event handling +const runner = mocha.run(); +runner.on('end', function() { + console.log('All tests finished'); +}); +``` + +### Browser Error Handling + +Enhanced error handling for browser environments with assertion integration. + +```javascript { .api } +/** + * Throw error directly into Mocha's error handling system + * Useful for integration with assertion libraries + * @param error - Error to throw + */ +mocha.throwError(error); +``` + +**Usage Example:** + +```javascript +// Integration with assertion libraries +function customAssert(condition, message) { + if (!condition) { + const error = new Error(message); + error.name = 'AssertionError'; + mocha.throwError(error); + } +} + +// Usage in tests +it('should handle custom assertions', function() { + customAssert(2 + 2 === 4, 'Math should work'); + customAssert(true === true, 'Truth should be true'); +}); +``` + +### Process Shim + +Browser-compatible process object for Node.js compatibility. + +```javascript { .api } +/** + * Browser process shim - limited process object for compatibility + */ +interface BrowserProcess { + /** + * Add event listener for uncaught exceptions + * @param event - Event name ('uncaughtException') + * @param handler - Error handler function + */ + on(event: 'uncaughtException', handler: (error: Error) => void): void; + + /** + * Remove event listener + * @param event - Event name + * @param handler - Handler function to remove + */ + removeListener(event: string, handler: Function): void; + + /** + * Get listener count for event + * @param event - Event name + * @returns {number} Number of listeners + */ + listenerCount(event: string): number; + + /** + * Get all listeners for event + * @param event - Event name + * @returns {Function[]} Array of listener functions + */ + listeners(event: string): Function[]; + + /** + * Standard output stream (browser-stdout shim) + */ + stdout: any; +} + +/** + * Access browser process shim + */ +const process = Mocha.process; +``` + +### Global Functions Export + +Browser-specific global function exports for ES module compatibility. + +```javascript { .api } +/** + * Global functions available in browser after setup + * These are automatically attached to window/global scope + */ + +// BDD interface functions (when ui: 'bdd') +function describe(title, fn); +function context(title, fn); // alias for describe +function it(title, fn); +function specify(title, fn); // alias for it + +// Skip functions +function xdescribe(title, fn); // skip suite +function xcontext(title, fn); // skip suite +function xit(title, fn); // skip test +function xspecify(title, fn); // skip test + +// Hook functions +function before(fn); // before all tests in suite +function beforeEach(fn); // before each test +function after(fn); // after all tests in suite +function afterEach(fn); // after each test + +/** + * ES module exports for import usage + * Available when using module bundlers + */ +export { + describe, context, it, specify, + xdescribe, xcontext, xit, xspecify, + before, beforeEach, after, afterEach +}; +``` + +### Browser-Specific Features + +Features and optimizations specific to browser environments. + +```javascript { .api } +/** + * High-performance timer override for browser + * Optimized immediate execution scheduling + */ +Mocha.Runner.immediately = function(callback) { + // Browser-optimized immediate execution +}; + +/** + * URL query parameter parsing for browser test configuration + * Automatically applied when mocha.run() is called + */ +interface URLQueryOptions { + grep?: string; // Filter tests by pattern + fgrep?: string; // Filter tests by fixed string + invert?: boolean; // Invert filter pattern +} + +// Example URL: test.html?grep=User&invert=true +// Automatically applies grep: 'User', invert: true +``` + +### HTML Reporter Integration + +Browser-specific HTML reporter with DOM integration and syntax highlighting. + +```javascript { .api } +/** + * HTML reporter automatically integrates with DOM + * Requires
element + */ + +/** + * HTML reporter features + */ +interface HTMLReporterFeatures { + /** + * Automatic syntax highlighting for code blocks + * Controlled by noHighlighting option + */ + syntaxHighlighting: boolean; + + /** + * Interactive test result filtering + */ + interactiveFiltering: boolean; + + /** + * Collapsible test suites + */ + collapsibleSuites: boolean; + + /** + * Real-time progress indication + */ + progressIndicator: boolean; +} + +/** + * HTML reporter DOM structure + */ +interface HTMLReporterDOM { + container: HTMLElement; // #mocha container + stats: HTMLElement; // Test statistics + tests: HTMLElement; // Test results + progress: HTMLElement; // Progress indicator +} +``` + +### Browser Loading Patterns + +Different approaches for loading Mocha in browsers. + +```javascript { .api } +/** + * Script tag loading (UMD build) + */ +// +// Creates global Mocha and mocha objects + +/** + * ES module loading (with bundler) + */ +import { describe, it, before, after } from 'mocha'; + +/** + * CommonJS loading (with bundler like Browserify) + */ +const { describe, it } = require('mocha'); + +/** + * AMD loading (with RequireJS) + */ +define(['mocha'], function(mocha) { + mocha.setup('bdd'); + return mocha; +}); +``` + +### Browser Compatibility + +Browser support and compatibility information. + +```javascript { .api } +/** + * Supported browsers (as of Mocha 11.7.2) + */ +interface BrowserSupport { + chrome: '>=60'; // Chrome 60+ + firefox: '>=55'; // Firefox 55+ + safari: '>=10'; // Safari 10+ + edge: '>=79'; // Chromium-based Edge + ie: false; // Internet Explorer not supported +} + +/** + * Required browser features + */ +interface RequiredFeatures { + es6: true; // ES6/ES2015 support required + promises: true; // Native Promise support + eventEmitter: true; // EventEmitter pattern support + json: true; // JSON parsing/stringifying + setTimeout: true; // Timer functions + console: true; // Console logging +} +``` + +### Browser Test Organization + +Best practices and patterns for organizing browser tests. + +```javascript { .api } +/** + * Recommended browser test structure + */ + +// test/browser/setup.js +mocha.setup({ + ui: 'bdd', + reporter: 'html', + timeout: 5000 +}); + +// test/browser/utils.js +function waitForElement(selector) { + return new Promise(resolve => { + const check = () => { + const el = document.querySelector(selector); + if (el) resolve(el); + else setTimeout(check, 10); + }; + check(); + }); +} + +// test/browser/dom-tests.js +describe('DOM Tests', function() { + beforeEach(function() { + document.body.innerHTML = '
'; + }); + + afterEach(function() { + document.body.innerHTML = ''; + }); + + it('should create DOM elements', async function() { + const app = document.getElementById('app'); + app.innerHTML = ''; + + const button = await waitForElement('button'); + assert(button.textContent === 'Click me'); + }); +}); + +// test/browser/run.js +mocha.run(function(failures) { + console.log(`Browser tests completed: ${failures} failures`); +}); +``` \ No newline at end of file diff --git a/.tessl/tiles/tessl/npm-mocha/docs/cli-config.md b/.tessl/tiles/tessl/npm-mocha/docs/cli-config.md new file mode 100644 index 000000000..a0e3dda58 --- /dev/null +++ b/.tessl/tiles/tessl/npm-mocha/docs/cli-config.md @@ -0,0 +1,457 @@ +# CLI and Configuration + +Command-line interface and comprehensive configuration system for running tests from the command line with file watching, parallel execution, and extensive customization options. + +## Capabilities + +### Command Line Interface + +Main CLI executable for running tests from the command line. + +```bash { .api } +# Basic usage +mocha [options] [files] + +# Common usage patterns +mocha # Run all tests in test/ directory +mocha test/**/*.spec.js # Run specific test files +mocha --grep "User" # Run tests matching pattern +mocha --reporter json # Use specific reporter +mocha --timeout 5000 # Set global timeout +mocha --watch # Watch files for changes +mocha --parallel # Run tests in parallel +``` + +### CLI Options + +Comprehensive command-line options for test configuration. + +```bash { .api } +# Test Selection and Filtering +--grep # Filter tests by pattern (string or regex) +--fgrep # Filter tests by fixed string +--invert # Invert grep pattern +--recursive # Look for tests in subdirectories + +# Test Execution +--timeout # Set global timeout (default: 2000ms) +--slow # Set slow test threshold (default: 75ms) +--retries # Set retry count for failed tests +--bail # Bail on first test failure +--parallel # Run tests in parallel +--jobs # Number of parallel jobs (default: CPU count - 1) + +# Interfaces and Reporters +--ui # Set interface: bdd, tdd, qunit, exports +--reporter # Set reporter (default: spec) +--reporter-option # Pass options to reporter + +# Test Behavior +--async-only # Force tests to be async +--allow-uncaught # Allow uncaught exceptions to propagate +--delay # Delay test execution until run() is called +--dry-run # Report tests without executing them +--exit # Force exit after tests complete +--forbid-only # Fail if .only tests are present +--forbid-pending # Fail if .skip tests are present +--full-trace # Display full stack traces + +# Global Variables and Leaks +--check-leaks # Check for global variable leaks +--globals # Specify global variables (comma-separated) + +# Output and Formatting +--colors # Force color output +--no-colors # Disable color output +--diff # Show diff on test failure +--inline-diffs # Show inline diffs +--sort # Sort test files alphabetically + +# File Operations +--watch # Watch files for changes and re-run tests +--watch-files # Specify files to watch (comma-separated) +--watch-ignore # Specify files to ignore when watching +--file # Include file before other test files +--require # Require module before running tests +--loader # Use custom loader for test files + +# Configuration Files +--config # Specify config file path +--package # Specify package.json path +--opts # Specify mocha.opts file (deprecated) + +# Node.js Specific +--inspect # Enable Node.js inspector +--inspect-brk # Enable inspector and break before start +--node-option