mirror of
https://github.com/codeflash-ai/codeflash.git
synced 2026-05-04 18:25:17 +00:00
Compare commits
156 commits
v0.20.5.po
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a2ec48fa3 | ||
|
|
33b4eb8e7a | ||
|
|
8aff48f392 | ||
|
|
e92e201fdf | ||
|
|
2b90ee846a | ||
|
|
1ba6af0a88 | ||
|
|
2908f76e64 | ||
|
|
f02b99f8fb | ||
|
|
c4ee5e1a2e | ||
|
|
f1521d7a2d | ||
|
|
efbd34159c | ||
|
|
0bf92290d2 | ||
|
|
e95f701ce3 | ||
|
|
c455256bfb | ||
|
|
e214ff7d1e | ||
|
|
7632ab671a | ||
|
|
259742d012 | ||
|
|
a80c996982 | ||
|
|
279ec47604 | ||
|
|
c172644987 | ||
|
|
c35e026cf8 | ||
|
|
41bf1d2d63 | ||
|
|
0eb4422b64 | ||
|
|
7367c2ec97 | ||
|
|
fc3792b704 | ||
|
|
d4e5381ee7 | ||
|
|
ff6070958b | ||
|
|
ae8522a12a | ||
|
|
8e38bca479 | ||
|
|
cb8e11af09 | ||
|
|
7e7cbee8c1 | ||
|
|
e125aeb712 | ||
|
|
82df3d38de | ||
|
|
3d7bb49b41 | ||
|
|
2054796acd | ||
|
|
db5b96a80c | ||
|
|
58c1bdf620 | ||
|
|
cfdb1315cb | ||
|
|
c613fda5de | ||
|
|
e78c92b70c | ||
|
|
5c0c90d265 | ||
|
|
8fe6b8fd56 | ||
|
|
25ba54e3e7 | ||
|
|
bf8a1e469e | ||
|
|
c0b728beff | ||
|
|
2c3e0f66e0 | ||
|
|
f39b953af0 | ||
|
|
adb1b556bf | ||
|
|
9a2a3f734d | ||
|
|
ba56064c72 | ||
|
|
5cb0a44cce | ||
|
|
3224f21cf7 | ||
|
|
92c8727495 | ||
|
|
ea57fba470 | ||
|
|
b2858dc328 | ||
|
|
dc5090e2dd | ||
|
|
d2ec01a0de | ||
|
|
531ba0bc2f | ||
|
|
91f603f78d | ||
|
|
0061739c03 | ||
|
|
c4bc18e233 | ||
|
|
892bff485d | ||
|
|
e4b1fb854b | ||
|
|
86e11dbb38 | ||
|
|
a396c62160 | ||
|
|
647eb4ba17 | ||
|
|
740c61a679 | ||
|
|
2b5eef8d20 | ||
|
|
bb3a447191 | ||
|
|
d7a4c762cf | ||
|
|
d4f4563f0d | ||
|
|
3080c1df80 | ||
|
|
a1d822801a | ||
|
|
6c58ac462b | ||
|
|
14be2aa1f8 | ||
|
|
d6d40ed431 | ||
|
|
e1a7569c94 | ||
|
|
d76c516e84 | ||
|
|
8956fdac22 | ||
|
|
970aeb4430 | ||
|
|
a3bb01243e | ||
|
|
14ca2c897d | ||
|
|
0232d84a7d | ||
|
|
a4b74fa500 | ||
|
|
9d9e7cd0ee | ||
|
|
2c79e50d68 | ||
|
|
972d88c108 | ||
|
|
83c87a75a1 | ||
|
|
67cf123929 | ||
|
|
1d26014d61 | ||
|
|
1112646e4e | ||
|
|
ef535b8834 | ||
|
|
a4473c3684 | ||
|
|
d8b62367ce | ||
|
|
3b8a2e5c82 | ||
|
|
ced8a746cd | ||
|
|
4d4cb5f517 | ||
|
|
819a56c33e | ||
|
|
a7371b55ca | ||
|
|
470482e824 | ||
|
|
b737f71e46 | ||
|
|
0cb67c1a17 | ||
|
|
5c778dfad4 | ||
|
|
40f16b565a | ||
|
|
cb87763a2d | ||
|
|
013c83f5e4 | ||
|
|
0d928f2b49 | ||
|
|
ecf4e63eca | ||
|
|
8959ead2f9 | ||
|
|
ec14860d29 | ||
|
|
151df774a4 | ||
|
|
b05561ef9e | ||
|
|
70260f22b3 | ||
|
|
82ec301fad | ||
|
|
986654b7e6 | ||
|
|
e191f74aa6 | ||
|
|
fefccd5935 | ||
|
|
bfe6f3a828 | ||
|
|
01e22152c7 | ||
|
|
e81f25f825 | ||
|
|
0772398c59 | ||
|
|
08aa94c54a | ||
|
|
46957e190f | ||
|
|
21f61ec93d | ||
|
|
2b0f633c0f | ||
|
|
5ee642e35e | ||
|
|
4ac573f10f | ||
|
|
72a41a5665 | ||
|
|
93810f8be6 | ||
|
|
79d47e0fae | ||
|
|
381d1319ea | ||
|
|
fe39d40e1b | ||
|
|
5a5b6e46ac | ||
|
|
4c3c6ea167 | ||
|
|
accbab4a16 | ||
|
|
2e2e19f7ae | ||
|
|
1a25f05e14 | ||
|
|
2208e8ca77 | ||
|
|
b533f50bdc | ||
|
|
61053be9ce | ||
|
|
436d642847 | ||
|
|
88babfef25 | ||
|
|
2fc528ebda | ||
|
|
992e91abc7 | ||
|
|
1e8e5d2cc2 | ||
|
|
a8c004164e | ||
|
|
05a7641405 | ||
|
|
70e3ce1a67 | ||
|
|
29879f19bc | ||
|
|
3b03249950 | ||
|
|
fdc7a52f33 | ||
|
|
8e2bab2e42 | ||
|
|
48e6835990 | ||
|
|
e3488bce6f | ||
|
|
3bd0255040 | ||
|
|
1cfcc3aee7 |
430 changed files with 117303 additions and 24097 deletions
45
.claude/hooks/bash-guard.sh
Executable file
45
.claude/hooks/bash-guard.sh
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env bash
|
||||
# PreToolUse hook: Block Bash calls that should use dedicated tools.
|
||||
# Exit 0 = allow, Exit 2 = block (message on stderr).
|
||||
|
||||
INPUT=$(cat 2>/dev/null || true)
|
||||
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null || true)
|
||||
|
||||
[ -z "$COMMAND" ] && exit 0
|
||||
|
||||
# Strip leading env vars (FOO=bar cmd ...) and whitespace to get the actual command
|
||||
STRIPPED=$(echo "$COMMAND" | sed 's/^[[:space:]]*\([A-Za-z_][A-Za-z0-9_]*=[^[:space:]]*[[:space:]]*\)*//')
|
||||
FIRST_CMD=$(echo "$STRIPPED" | awk '{print $1}')
|
||||
|
||||
case "$FIRST_CMD" in
|
||||
grep|egrep|fgrep|rg)
|
||||
echo "BLOCKED: Use the Grep tool instead of \`$FIRST_CMD\`. It provides better output and permissions handling." >&2
|
||||
exit 2
|
||||
;;
|
||||
find)
|
||||
echo "BLOCKED: Use the Glob tool instead of \`find\`. Glob is faster and returns results sorted by modification time." >&2
|
||||
exit 2
|
||||
;;
|
||||
cat|head|tail)
|
||||
echo "BLOCKED: Use the Read tool instead of \`$FIRST_CMD\`. Read provides line numbers and supports images/PDFs." >&2
|
||||
exit 2
|
||||
;;
|
||||
awk)
|
||||
echo "BLOCKED: Use the Grep tool or Read tool instead of \`awk\`." >&2
|
||||
exit 2
|
||||
;;
|
||||
sed)
|
||||
if echo "$COMMAND" | grep -qE '(^|[[:space:]])sed[[:space:]]+-i'; then
|
||||
echo "BLOCKED: Use the Edit tool instead of \`sed -i\`. Edit tracks changes properly." >&2
|
||||
exit 2
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# echo with file redirection (echo "..." > file)
|
||||
if echo "$STRIPPED" | grep -qE '^echo\b.*[[:space:]]>'; then
|
||||
echo "BLOCKED: Use the Write tool instead of \`echo >\`. Write provides proper file creation." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
47
.claude/hooks/post-compact.sh
Executable file
47
.claude/hooks/post-compact.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/usr/bin/env bash
|
||||
# PreCompact hook: Inject state preservation guidance before context compaction.
|
||||
|
||||
cd "$CLAUDE_PROJECT_DIR" 2>/dev/null || exit 0
|
||||
|
||||
STATE=""
|
||||
|
||||
BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
[ -n "$BRANCH" ] && STATE="${STATE}Branch: ${BRANCH}\n"
|
||||
|
||||
DIRTY=$(git status --porcelain 2>/dev/null)
|
||||
if [ -n "$DIRTY" ]; then
|
||||
COUNT=$(echo "$DIRTY" | wc -l | tr -d ' ')
|
||||
STATE="${STATE}Uncommitted files (${COUNT}):\n${DIRTY}\n"
|
||||
fi
|
||||
|
||||
UPSTREAM=$(git rev-parse --abbrev-ref '@{upstream}' 2>/dev/null)
|
||||
if [ -n "$UPSTREAM" ]; then
|
||||
AHEAD=$(git rev-list --count "${UPSTREAM}..HEAD" 2>/dev/null)
|
||||
[ "$AHEAD" -gt 0 ] 2>/dev/null && STATE="${STATE}Unpushed commits: ${AHEAD}\n"
|
||||
fi
|
||||
|
||||
RECENT=$(git log --oneline -5 2>/dev/null)
|
||||
[ -n "$RECENT" ] && STATE="${STATE}Recent commits:\n${RECENT}\n"
|
||||
|
||||
LATEST_HANDOFF=$(ls -t "$CLAUDE_PROJECT_DIR/.claude/handoffs/"*.md 2>/dev/null | head -1)
|
||||
if [ -n "$LATEST_HANDOFF" ] && [ -f "$LATEST_HANDOFF" ]; then
|
||||
HANDOFF_CONTENT=$(head -40 "$LATEST_HANDOFF" 2>/dev/null)
|
||||
[ -n "$HANDOFF_CONTENT" ] && STATE="${STATE}\nHandoff context:\n${HANDOFF_CONTENT}\n"
|
||||
fi
|
||||
|
||||
STATE="${STATE}\nProject conventions to preserve:\n"
|
||||
STATE="${STATE}- Python 3.9+, uv for all tooling, ruff + mypy via prek\n"
|
||||
STATE="${STATE}- Verification: uv run prek (single command for lint/format/types)\n"
|
||||
STATE="${STATE}- Pre-push: uv run prek run --from-ref origin/<base>\n"
|
||||
STATE="${STATE}- Conventional commits: fix:, feat:, refactor:, test:, chore:\n"
|
||||
STATE="${STATE}- Result type: Success(value) / Failure(error), check with is_successful()\n"
|
||||
STATE="${STATE}- Language singleton: set_current_language() / current_language()\n"
|
||||
STATE="${STATE}- libcst for code transforms, ast for read-only analysis\n"
|
||||
|
||||
[ -z "$STATE" ] && exit 0
|
||||
|
||||
EXPANDED=$(printf '%b' "$STATE")
|
||||
jq -n --arg msg "PRESERVE the following session state through compaction:
|
||||
$EXPANDED" '{"systemMessage": $msg}'
|
||||
|
||||
exit 0
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
# Everyone is on macOS so this should be fine, we don't account for Windows
|
||||
set -euo pipefail
|
||||
|
||||
input=$(cat)
|
||||
|
|
@ -10,6 +9,5 @@ if [[ -z "$file_path" || ! -f "$file_path" ]]; then
|
|||
fi
|
||||
|
||||
if [[ "$file_path" == *.py ]]; then
|
||||
# First run auto-fixes formatting; second run catches real lint errors
|
||||
uv run prek --files "$file_path" 2>/dev/null || uv run prek --files "$file_path"
|
||||
fi
|
||||
|
|
|
|||
25
.claude/hooks/require-read.sh
Executable file
25
.claude/hooks/require-read.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
# PreToolUse hook: Block Write/Edit on existing files that haven't been Read first.
|
||||
# Exit 0 = allow, Exit 2 = block (message on stderr).
|
||||
|
||||
INPUT=$(cat 2>/dev/null || true)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || true)
|
||||
|
||||
[ -z "$FILE_PATH" ] && exit 0
|
||||
|
||||
# New files don't need prior reads
|
||||
[ ! -f "$FILE_PATH" ] && exit 0
|
||||
|
||||
TRACKER="$CLAUDE_PROJECT_DIR/.claude/.read-tracker"
|
||||
|
||||
if [ ! -f "$TRACKER" ]; then
|
||||
echo "BLOCKED: Read \`$(basename "$FILE_PATH")\` first before modifying it." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if grep -qxF "$FILE_PATH" "$TRACKER"; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "BLOCKED: Read \`$(basename "$FILE_PATH")\` first before modifying it." >&2
|
||||
exit 2
|
||||
50
.claude/hooks/status-line.sh
Executable file
50
.claude/hooks/status-line.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env bash
|
||||
# Status line: derive context from git state.
|
||||
|
||||
input=$(cat)
|
||||
project_dir=$(echo "$input" | jq -r '.workspace.project_dir')
|
||||
|
||||
user=$(whoami)
|
||||
branch=$(git -C "$project_dir" branch --show-current 2>/dev/null)
|
||||
|
||||
changed=$(git -C "$project_dir" diff --name-only HEAD 2>/dev/null)
|
||||
[ -z "$changed" ] && changed=$(git -C "$project_dir" diff --name-only 2>/dev/null)
|
||||
[ -z "$changed" ] && changed=$(git -C "$project_dir" diff --name-only --cached 2>/dev/null)
|
||||
|
||||
if [ -n "$changed" ]; then
|
||||
area=$(echo "$changed" | sed 's|/.*||' | sort | uniq -c | sort -rn | head -1 | awk '{print $2}')
|
||||
else
|
||||
area=""
|
||||
fi
|
||||
|
||||
context=""
|
||||
case "$area" in
|
||||
codeflash)
|
||||
subsystem=$(echo "$changed" | grep '^codeflash/' | sed 's|^codeflash/||; s|/.*||' | sort | uniq -c | sort -rn | head -1 | awk '{print $2}')
|
||||
[ -n "$subsystem" ] && context="editing $subsystem" ;;
|
||||
tests)
|
||||
target=$(echo "$changed" | grep '^tests/' | sed 's|^tests/||; s|/.*||' | sort -u | head -1)
|
||||
[ -n "$target" ] && context="testing $target" ;;
|
||||
.claude)
|
||||
context="configuring claude" ;;
|
||||
esac
|
||||
|
||||
if [ -z "$context" ] && [ -n "$branch" ]; then
|
||||
case "$branch" in
|
||||
feat/*|cf-*) context="building: ${branch#feat/}" ;;
|
||||
fix/*) context="fixing: ${branch#fix/}" ;;
|
||||
refactor/*) context="refactoring: ${branch#refactor/}" ;;
|
||||
test/*) context="testing: ${branch#test/}" ;;
|
||||
chore/*) context="chore: ${branch#chore/}" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
dirty=""
|
||||
if [ -n "$(git -C "$project_dir" status --porcelain 2>/dev/null)" ]; then
|
||||
dirty=" *"
|
||||
fi
|
||||
|
||||
status="$user | codeflash"
|
||||
[ -n "$context" ] && status="$status | $context"
|
||||
[ -n "$branch" ] && status="$status | $branch$dirty"
|
||||
echo "$status"
|
||||
11
.claude/hooks/track-read.sh
Executable file
11
.claude/hooks/track-read.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
# PostToolUse hook: Track Read calls for the require-read guard.
|
||||
|
||||
INPUT=$(cat 2>/dev/null || true)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null || true)
|
||||
|
||||
[ -z "$FILE_PATH" ] && exit 0
|
||||
|
||||
TRACKER="$CLAUDE_PROJECT_DIR/.claude/.read-tracker"
|
||||
grep -qxF "$FILE_PATH" "$TRACKER" 2>/dev/null || echo "$FILE_PATH" >> "$TRACKER"
|
||||
exit 0
|
||||
|
|
@ -4,10 +4,11 @@
|
|||
- **Python**: 3.9+ syntax
|
||||
- **Package management**: Always use `uv`, never `pip`
|
||||
- **Tooling**: Ruff for linting/formatting, mypy strict mode, prek for pre-commit checks
|
||||
- **Comments**: Minimal - only explain "why", not "what"
|
||||
- **Docstrings**: Do not add docstrings to new or changed code unless the user explicitly asks for them — not even one-liners. The codebase intentionally keeps functions self-documenting through clear naming and type annotations
|
||||
- **Types**: Match the type annotation style of surrounding code — the codebase uses annotations, so add them in new code
|
||||
- **Naming**: NEVER use leading underscores (`_function_name`) - Python has no true private functions, use public names
|
||||
- **Comments**: Minimal — only explain "why", not "what"
|
||||
- **Docstrings**: Do not add docstrings unless the user explicitly asks
|
||||
- **Types**: Match the type annotation style of surrounding code
|
||||
- **Naming**: No leading underscores (`_function_name`) — Python has no true private functions
|
||||
- **Paths**: Always use absolute paths
|
||||
- **Encoding**: Always pass `encoding="utf-8"` to `open()`, `read_text()`, `write_text()`, etc. in new or changed code — Windows defaults to `cp1252` which breaks on non-ASCII content. Don't flag pre-existing code that lacks it unless you're already modifying that line.
|
||||
- **Verification**: Use `uv run prek` to verify code — it handles ruff, ty, mypy in one pass. Don't run `ruff`, `mypy`, or `python -c "import ..."` separately; `prek` is the single verification command
|
||||
- **Encoding**: Always pass `encoding="utf-8"` to `open()`, `read_text()`, `write_text()` in new or changed code
|
||||
- **Verification**: Use `uv run prek` — it handles ruff, ty, mypy in one pass. Don't run them separately
|
||||
- **Code transforms**: Use `libcst` for code modification/transformation. `ast` is acceptable for read-only analysis
|
||||
|
|
|
|||
19
.claude/rules/debugging.md
Normal file
19
.claude/rules/debugging.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Debugging
|
||||
|
||||
## Root cause first
|
||||
|
||||
When encountering a bug, investigate the root cause. Don't patch symptoms. If you're about to add a try/except, a fallback default, or a defensive check — ask whether the real fix is upstream.
|
||||
|
||||
## Isolated testing
|
||||
|
||||
Prefer running individual test functions over full suites. Only run the full suite when explicitly asked or before pushing.
|
||||
|
||||
- Single function: `uv run pytest tests/test_foo.py::TestBar::test_baz -v`
|
||||
- Single module: `uv run pytest tests/test_foo.py -v`
|
||||
- Full suite: only when asked, or before `git push`
|
||||
|
||||
When debugging a specific endpoint or integration, test it directly instead of running the entire pipeline end-to-end.
|
||||
|
||||
## Subprocess failures
|
||||
|
||||
When a subprocess fails, always log stdout and stderr. "Exit code 1" with no output is useless.
|
||||
|
|
@ -1,19 +1,35 @@
|
|||
# Git Commits & Pull Requests
|
||||
# Git
|
||||
|
||||
## Commits
|
||||
|
||||
- Never commit, amend, or push without explicit permission
|
||||
- Don't commit intermediate states — wait until the full implementation is complete, reviewed, and explicitly approved before committing. If the user corrects direction mid-implementation, incorporate the correction before any commit
|
||||
- Always create a new branch from `main` before starting any new work — never commit directly to `main` or reuse an existing feature branch for unrelated changes
|
||||
- Use conventional commit format: `fix:`, `feat:`, `refactor:`, `docs:`, `test:`, `chore:`
|
||||
- Keep commits atomic - one logical change per commit
|
||||
- Commit message body should be concise (1-2 sentences max)
|
||||
- Merge for simple syncs, rebase when branches have diverged significantly
|
||||
- When committing to an external/third-party repo, follow that repo's own conventions for versioning, changelog, and CI
|
||||
- Pre-commit: Run `uv run prek` before committing — fix any issues before creating the commit
|
||||
- Pre-push: Run `uv run prek run --from-ref origin/<base>` to check all changed files against the PR base — this matches CI behavior and catches issues that per-commit prek misses. To detect the base branch: `gh pr view --json baseRefName -q .baseRefName 2>/dev/null || echo main`
|
||||
- Don't commit intermediate states — wait until the full implementation is complete and approved
|
||||
- Always create a new branch from `main` — never commit directly to `main`
|
||||
- Conventional format: `fix:`, `feat:`, `refactor:`, `docs:`, `test:`, `chore:`
|
||||
- First line: imperative verb + what changed, under 72 characters
|
||||
- Body for *why*, not *what* — the diff shows what changed
|
||||
- One purpose per commit: a bug fix, a new function, a refactor — not all three
|
||||
- A commit that adds a function also adds its tests and exports — that's one logical change
|
||||
|
||||
## Sizing
|
||||
|
||||
- Too small: renaming a variable in one commit, updating its references in another
|
||||
- Right size: adding a function with its tests, `__init__` export, and usage update
|
||||
- Too large: implementing an entire subsystem in one commit
|
||||
|
||||
## Pre-commit / Pre-push
|
||||
|
||||
- Pre-commit: Run `uv run prek` before committing
|
||||
- Pre-push: Run `uv run prek run --from-ref origin/<base>` to check all changed files against the PR base
|
||||
|
||||
## Pull Requests
|
||||
- PR titles should use conventional format
|
||||
- Keep the PR body short and straight to the point
|
||||
|
||||
- PR titles use conventional format
|
||||
- Keep the PR body short and to the point
|
||||
- If related to a Linear issue, include `CF-#` in the body
|
||||
- Branch naming: `cf-#-title` (lowercase, hyphenated), no other prefixes/suffixes
|
||||
- Branch naming: `cf-#-title` (lowercase, hyphenated)
|
||||
|
||||
## Branch Hygiene
|
||||
|
||||
- Delete feature branches locally after merging (`git branch -d <branch>`)
|
||||
- Use `/clean_gone` to prune local branches whose remote tracking branch has been deleted
|
||||
|
|
|
|||
5
.claude/rules/github.md
Normal file
5
.claude/rules/github.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# GitHub Interactions
|
||||
|
||||
ALWAYS use MCP GitHub tools (`mcp__github__*`) for GitHub operations. Check for a matching MCP tool first — only fall back to `gh` via Bash when no MCP tool exists for the operation.
|
||||
|
||||
This also applies to other MCP-connected services (Linear, Granola). MCP first, CLI second.
|
||||
|
|
@ -6,8 +6,8 @@ paths:
|
|||
# Language Support Patterns
|
||||
|
||||
- Current language is a module-level singleton in `languages/current.py` — use `set_current_language()` / `current_language()`, never pass language as a parameter through call chains
|
||||
- Use `get_language_support(identifier)` from `languages/registry.py` to get a `LanguageSupport` instance — never import language classes directly
|
||||
- New language support classes must use the `@register_language` decorator to register with the extension and language registries
|
||||
- `languages/__init__.py` uses `__getattr__` for lazy imports to avoid circular dependencies — follow this pattern when adding new exports
|
||||
- Prefer `LanguageSupport` protocol dispatch over `is_python()`/`is_javascript()` guards — remaining guards are being migrated to protocol methods
|
||||
- Use `get_language_support(identifier)` from `languages/registry.py` — never import language classes directly
|
||||
- New language support classes must use the `@register_language` decorator
|
||||
- `languages/__init__.py` uses `__getattr__` for lazy imports to avoid circular dependencies
|
||||
- Prefer `LanguageSupport` protocol dispatch over `is_python()`/`is_javascript()` guards
|
||||
- `is_javascript()` returns `True` for both JavaScript and TypeScript (still used in ~15 call sites pending migration)
|
||||
|
|
|
|||
27
.claude/rules/sessions.md
Normal file
27
.claude/rules/sessions.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Session Discipline
|
||||
|
||||
## Scope
|
||||
|
||||
One task per session. Don't mix implementation with communication drafting, transcript search, or strategic planning.
|
||||
|
||||
## Duration
|
||||
|
||||
Cap sessions at 2-3 hours. Use `/handoff` at natural breakpoints rather than letting auto-compaction degrade context.
|
||||
|
||||
- After 1 compaction: consider wrapping up the current task and handing off
|
||||
- After 3 compactions: stop, and tell the user to start a fresh session
|
||||
- Never continue past 5 compactions — context is too degraded
|
||||
|
||||
## Context preservation
|
||||
|
||||
When compacting, preserve: modified files list, current branch, test commands used, key decisions made. Use subagents for exploration to keep main context clean.
|
||||
|
||||
## No polling
|
||||
|
||||
Never poll background tasks. No `wc -l`, no `tail -f`, no `sleep` loops. Use `run_in_background` and wait for the completion notification.
|
||||
|
||||
## File read budget
|
||||
|
||||
If you've read the same file 3+ times in a session, either:
|
||||
- The session is too long and compaction destroyed your context — write a handoff
|
||||
- You're not retaining key information — write it down in your response before it compacts away
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
paths:
|
||||
- "codeflash/**/*.py"
|
||||
---
|
||||
|
||||
# Source Code Rules
|
||||
|
||||
- Use `libcst` for code modification/transformation to preserve formatting. `ast` is acceptable for read-only analysis and parsing.
|
||||
|
|
@ -4,13 +4,14 @@ paths:
|
|||
- "codeflash/**/*test*.py"
|
||||
---
|
||||
|
||||
# Testing Conventions
|
||||
# Testing
|
||||
|
||||
- Code context extraction and replacement tests must always assert for full string equality, no substring matching.
|
||||
- Use pytest's `tmp_path` fixture for temp directories — do not use `tempfile.mkdtemp()`, `tempfile.TemporaryDirectory()`, or `NamedTemporaryFile`. Some existing tests still use `tempfile` but new tests must use `tmp_path`.
|
||||
- Always call `.resolve()` on Path objects before passing them to functions under test — this ensures absolute paths and resolves symlinks. Example: `source_file = (tmp_path / "example.py").resolve()`
|
||||
- Use `.as_posix()` when converting resolved paths to strings (normalizes to forward slashes).
|
||||
- Any new feature or bug fix that can be tested automatically must have test cases.
|
||||
- If changes affect existing test expectations, update the tests accordingly. Tests must always pass after changes.
|
||||
- The pytest plugin patches `time`, `random`, `uuid`, and `datetime` for deterministic test execution — never assume real randomness or real time in verification tests.
|
||||
- `conftest.py` uses an autouse fixture that calls `reset_current_language()` — tests always start with Python as the default language.
|
||||
- Full string equality for context extraction/replacement tests — no substring matching
|
||||
- Use pytest's `tmp_path` fixture — not `tempfile.mkdtemp()` or `NamedTemporaryFile`
|
||||
- Always call `.resolve()` on Path objects before passing to functions under test
|
||||
- Use `.as_posix()` when converting resolved paths to strings
|
||||
- New features and bug fixes must have test cases
|
||||
- The pytest plugin patches `time`, `random`, `uuid`, `datetime` for deterministic execution
|
||||
- `conftest.py` autouse fixture calls `reset_current_language()` — tests start with Python as default
|
||||
- Prefer running individual tests over full suites: `uv run pytest tests/test_foo.py::TestBar::test_baz -v`
|
||||
- Only run the full suite when explicitly asked or before pushing
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
# Workflow
|
||||
|
||||
## Code Changes
|
||||
- Before making any changes, outline your approach in 3-5 numbered steps. Include which repo/branch you'll work in, what commands you'll run, and what success looks like. Wait for approval before starting
|
||||
|
||||
Before making any changes, outline your approach in 3-5 numbered steps. Include which branch you'll work on, what commands you'll run, and what success looks like. Wait for approval before starting.
|
||||
|
||||
## Response Style
|
||||
- When listing items (PRs, functions, optimization targets), always provide the complete list ordered by priority on the first attempt. Do not give partial lists
|
||||
|
||||
When listing items (PRs, functions, optimization targets), provide the complete list ordered by priority on the first attempt. No partial lists.
|
||||
|
||||
## Commands
|
||||
- When running long-running commands (benchmarks, profiling, optimizers like codeflash), always run them in the foreground. Do not use background processes
|
||||
|
||||
Long-running commands (benchmarks, profiling, optimizers) always run in the foreground. Do not use background processes.
|
||||
|
||||
## Debugging
|
||||
- When claiming something is a pre-existing issue (e.g., test failures on main), verify by checking out main and running the tests before making that claim
|
||||
|
||||
When claiming something is a pre-existing issue (e.g., test failures on main), verify by checking out main and running the tests before making that claim.
|
||||
|
|
|
|||
|
|
@ -1,16 +1,89 @@
|
|||
{
|
||||
"attribution": {
|
||||
"commit": "",
|
||||
"pr": ""
|
||||
},
|
||||
"includeCoAuthoredBy": false,
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git status*)",
|
||||
"Bash(git diff*)",
|
||||
"Bash(git log*)",
|
||||
"Bash(git branch*)",
|
||||
"Bash(git show*)",
|
||||
"Bash(git fetch*)",
|
||||
"Bash(git checkout*)",
|
||||
"Bash(uv run*)",
|
||||
"Bash(uv sync*)",
|
||||
"Bash(uv pip*)",
|
||||
"Bash(prek*)",
|
||||
"Bash(make*)",
|
||||
"Bash(gh *)"
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/bash-guard.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/require-read.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Read",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/track-read.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Edit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": ".claude/hooks/post-edit-lint.sh",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-lint.sh",
|
||||
"timeout": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-compact.sh",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"statusLine": {
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/status-line.sh"
|
||||
},
|
||||
"enableAllProjectMcpServers": true,
|
||||
"env": {
|
||||
"ENABLE_LSP_TOOL": "1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ uv run mypy --non-interactive --config-file pyproject.toml <changed_files>
|
|||
```
|
||||
|
||||
- Fix type annotation issues: missing return types, incorrect types, Optional/None unions, import errors for type hints
|
||||
- Do NOT add `# type: ignore` comments — always fix the root cause
|
||||
- Do NOT add `# type: ignore` comments -- always fix the root cause
|
||||
- Do NOT fix type errors that require logic changes, complex generic type rework, or anything that could change runtime behavior
|
||||
- Files in `mypy_allowlist.txt` are checked in CI — ensure they remain error-free
|
||||
- Files in `mypy_allowlist.txt` are checked in CI -- ensure they remain error-free
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ When prek (pre-commit) checks fail:
|
|||
1. Run `uv run prek run` to see failures (local, checks staged files)
|
||||
2. In CI, the equivalent is `uv run prek run --from-ref origin/main`
|
||||
3. prek runs ruff format, ruff check, and mypy on changed files
|
||||
4. Fix issues in order: formatting → lint → type errors
|
||||
4. Fix issues in order: formatting -> lint -> type errors
|
||||
5. Re-run `uv run prek run` to verify all checks pass
|
||||
|
|
|
|||
0
.codeflash/benchmarks/__init__.py
Normal file
0
.codeflash/benchmarks/__init__.py
Normal file
|
|
@ -1,31 +1,18 @@
|
|||
from argparse import Namespace
|
||||
from pathlib import Path
|
||||
|
||||
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
||||
from codeflash.languages.python.context.code_context_extractor import get_code_optimization_context
|
||||
from codeflash.models.models import FunctionParent
|
||||
from codeflash.optimization.optimizer import Optimizer
|
||||
|
||||
|
||||
def test_benchmark_extract(benchmark) -> None:
|
||||
file_path = Path(__file__).parent.parent.parent.resolve() / "codeflash"
|
||||
opt = Optimizer(
|
||||
Namespace(
|
||||
project_root=file_path.resolve(),
|
||||
disable_telemetry=True,
|
||||
tests_root=(file_path / "tests").resolve(),
|
||||
test_framework="pytest",
|
||||
pytest_cmd="pytest",
|
||||
experiment_id=None,
|
||||
test_project_root=Path.cwd(),
|
||||
)
|
||||
)
|
||||
project_root = Path(__file__).parent.parent.parent.resolve() / "codeflash"
|
||||
function_to_optimize = FunctionToOptimize(
|
||||
function_name="replace_function_and_helpers_with_optimized_code",
|
||||
file_path=file_path / "languages" / "function_optimizer.py",
|
||||
file_path=project_root / "languages" / "function_optimizer.py",
|
||||
parents=[FunctionParent(name="FunctionOptimizer", type="ClassDef")],
|
||||
starting_line=None,
|
||||
ending_line=None,
|
||||
)
|
||||
|
||||
benchmark(get_code_optimization_context, function_to_optimize, opt.args.project_root)
|
||||
benchmark(get_code_optimization_context, function_to_optimize, project_root)
|
||||
133
.codeflash/benchmarks/test_benchmark_comparator.py
Normal file
133
.codeflash/benchmarks/test_benchmark_comparator.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
"""Benchmark comparator type dispatch performance.
|
||||
|
||||
Exercises the fast-path frozenset lookup vs isinstance MRO traversal
|
||||
across realistic return value shapes: primitives, nested containers,
|
||||
and mixed-type structures typical of real optimization verification.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
|
||||
from codeflash.verification.comparator import comparator
|
||||
|
||||
# --- Test data: realistic return value shapes ---
|
||||
|
||||
# 1. Flat primitives (int, bool, None, str, float, bytes) — the fast-path sweet spot
|
||||
_PRIMITIVES_A = [
|
||||
42,
|
||||
True,
|
||||
None,
|
||||
3.14,
|
||||
"hello",
|
||||
b"bytes",
|
||||
0,
|
||||
False,
|
||||
"",
|
||||
1.0,
|
||||
-1,
|
||||
None,
|
||||
True,
|
||||
99,
|
||||
"world",
|
||||
b"\x00\x01",
|
||||
2**31,
|
||||
0.0,
|
||||
False,
|
||||
None,
|
||||
]
|
||||
_PRIMITIVES_B = list(_PRIMITIVES_A)
|
||||
|
||||
# 2. Nested dict of lists (common return value shape: API responses, parsed configs)
|
||||
_NESTED_DICT_A = {
|
||||
"users": [{"id": i, "name": f"user_{i}", "active": i % 2 == 0, "score": i * 1.5} for i in range(50)],
|
||||
"metadata": {"total": 50, "page": 1, "has_next": True},
|
||||
"tags": [f"tag_{i}" for i in range(20)],
|
||||
"config": {"timeout": 30, "retries": 3, "debug": False, "threshold": Decimal("0.95")},
|
||||
}
|
||||
_NESTED_DICT_B = {
|
||||
"users": [{"id": i, "name": f"user_{i}", "active": i % 2 == 0, "score": i * 1.5} for i in range(50)],
|
||||
"metadata": {"total": 50, "page": 1, "has_next": True},
|
||||
"tags": [f"tag_{i}" for i in range(20)],
|
||||
"config": {"timeout": 30, "retries": 3, "debug": False, "threshold": Decimal("0.95")},
|
||||
}
|
||||
|
||||
# 3. List of tuples (common: database rows, CSV data)
|
||||
_ROWS_A = [(i, f"row_{i}", i * 0.1, i % 3 == 0, None if i % 5 == 0 else i) for i in range(200)]
|
||||
_ROWS_B = [(i, f"row_{i}", i * 0.1, i % 3 == 0, None if i % 5 == 0 else i) for i in range(200)]
|
||||
|
||||
|
||||
# 4. Deeply nested structure (worst case for recursive comparator)
|
||||
def _make_deep(depth: int) -> dict:
|
||||
if depth == 0:
|
||||
return {"leaf": True, "value": 42, "items": [1, 2, 3], "label": "end"}
|
||||
return {"level": depth, "child": _make_deep(depth - 1), "siblings": list(range(depth))}
|
||||
|
||||
|
||||
_DEEP_A = _make_deep(15)
|
||||
_DEEP_B = _make_deep(15)
|
||||
|
||||
# 5. Mixed identity types (frozenset, range, slice, OrderedDict, bytes, complex)
|
||||
_IDENTITY_TYPES_A = [
|
||||
frozenset({1, 2, 3}),
|
||||
range(100),
|
||||
complex(1, 2),
|
||||
Decimal("3.14"),
|
||||
OrderedDict(a=1, b=2),
|
||||
b"binary",
|
||||
bytearray(b"mutable"),
|
||||
memoryview(b"view"),
|
||||
type(None),
|
||||
True,
|
||||
42,
|
||||
None,
|
||||
] * 10
|
||||
_IDENTITY_TYPES_B = list(_IDENTITY_TYPES_A)
|
||||
|
||||
|
||||
def _compare_all_primitives() -> None:
|
||||
for a, b in zip(_PRIMITIVES_A, _PRIMITIVES_B):
|
||||
comparator(a, b)
|
||||
|
||||
|
||||
def _compare_nested_dict() -> None:
|
||||
comparator(_NESTED_DICT_A, _NESTED_DICT_B)
|
||||
|
||||
|
||||
def _compare_rows() -> None:
|
||||
comparator(_ROWS_A, _ROWS_B)
|
||||
|
||||
|
||||
def _compare_deep() -> None:
|
||||
comparator(_DEEP_A, _DEEP_B)
|
||||
|
||||
|
||||
def _compare_identity_types() -> None:
|
||||
for a, b in zip(_IDENTITY_TYPES_A, _IDENTITY_TYPES_B):
|
||||
comparator(a, b)
|
||||
|
||||
|
||||
def test_benchmark_comparator_primitives(benchmark) -> None:
|
||||
"""20 flat primitive comparisons (int, bool, None, str, float, bytes)."""
|
||||
benchmark(_compare_all_primitives)
|
||||
|
||||
|
||||
def test_benchmark_comparator_nested_dict(benchmark) -> None:
|
||||
"""Nested dict with 50-element user list, metadata, tags, config."""
|
||||
benchmark(_compare_nested_dict)
|
||||
|
||||
|
||||
def test_benchmark_comparator_rows(benchmark) -> None:
|
||||
"""200 tuples of (int, str, float, bool, Optional[int])."""
|
||||
benchmark(_compare_rows)
|
||||
|
||||
|
||||
def test_benchmark_comparator_deep(benchmark) -> None:
|
||||
"""15-level deep nested dict structure."""
|
||||
benchmark(_compare_deep)
|
||||
|
||||
|
||||
def test_benchmark_comparator_identity_types(benchmark) -> None:
|
||||
"""120 frozenset/range/complex/Decimal/OrderedDict/bytes comparisons."""
|
||||
benchmark(_compare_identity_types)
|
||||
75
.codeflash/benchmarks/test_benchmark_libcst_multi_file.py
Normal file
75
.codeflash/benchmarks/test_benchmark_libcst_multi_file.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
"""Benchmark libcst visitor performance across many files.
|
||||
|
||||
Exercises the visitor-heavy codepaths that benefit from the libcst dispatch
|
||||
table cache: discover_functions + get_code_optimization_context on multiple
|
||||
real source files.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
||||
from codeflash.languages.python.context.code_context_extractor import get_code_optimization_context
|
||||
from codeflash.languages.python.support import PythonSupport
|
||||
from codeflash.models.models import FunctionParent
|
||||
|
||||
# Real source files from the codeflash codebase, chosen for size and visitor diversity.
|
||||
_CODEFLASH_ROOT = Path(__file__).parent.parent.parent.resolve() / "codeflash"
|
||||
|
||||
_SOURCE_FILES: list[Path] = [
|
||||
_CODEFLASH_ROOT / "languages" / "function_optimizer.py",
|
||||
_CODEFLASH_ROOT / "languages" / "python" / "context" / "code_context_extractor.py",
|
||||
_CODEFLASH_ROOT / "languages" / "python" / "support.py",
|
||||
_CODEFLASH_ROOT / "languages" / "python" / "static_analysis" / "code_extractor.py",
|
||||
_CODEFLASH_ROOT / "languages" / "python" / "static_analysis" / "code_replacer.py",
|
||||
_CODEFLASH_ROOT / "code_utils" / "instrument_existing_tests.py",
|
||||
_CODEFLASH_ROOT / "benchmarking" / "compare.py",
|
||||
_CODEFLASH_ROOT / "models" / "models.py",
|
||||
_CODEFLASH_ROOT / "discovery" / "discover_unit_tests.py",
|
||||
_CODEFLASH_ROOT / "languages" / "base.py",
|
||||
]
|
||||
|
||||
# For each file, pick one top-level function to extract context for.
|
||||
# (class, function_name) — class=None means module-level.
|
||||
_TARGETS: list[tuple[Path, str | None, str]] = [
|
||||
(_SOURCE_FILES[0], "FunctionOptimizer", "replace_function_and_helpers_with_optimized_code"),
|
||||
(_SOURCE_FILES[1], None, "get_code_optimization_context"),
|
||||
(_SOURCE_FILES[2], "PythonSupport", "discover_functions"),
|
||||
(_SOURCE_FILES[3], None, "add_global_assignments"),
|
||||
(_SOURCE_FILES[4], None, "replace_functions_in_file"),
|
||||
(_SOURCE_FILES[5], None, "inject_profiling_into_existing_test"),
|
||||
(_SOURCE_FILES[6], None, "compare_branches"),
|
||||
(_SOURCE_FILES[7], None, "get_comment_prefix"),
|
||||
(_SOURCE_FILES[8], None, "discover_unit_tests"),
|
||||
(_SOURCE_FILES[9], None, "convert_parents_to_tuple"),
|
||||
]
|
||||
|
||||
|
||||
def _discover_all() -> None:
|
||||
"""Run discover_functions on all source files."""
|
||||
ps = PythonSupport()
|
||||
for file_path in _SOURCE_FILES:
|
||||
source = file_path.read_text(encoding="utf-8")
|
||||
ps.discover_functions(source=source, file_path=file_path)
|
||||
|
||||
|
||||
def _extract_all_contexts() -> None:
|
||||
"""Run get_code_optimization_context on every target function."""
|
||||
project_root = _CODEFLASH_ROOT.parent
|
||||
for file_path, class_name, func_name in _TARGETS:
|
||||
parents = [FunctionParent(name=class_name, type="ClassDef")] if class_name else []
|
||||
fto = FunctionToOptimize(
|
||||
function_name=func_name, file_path=file_path, parents=parents, starting_line=None, ending_line=None
|
||||
)
|
||||
get_code_optimization_context(fto, project_root)
|
||||
|
||||
|
||||
def test_benchmark_discover_functions_multi_file(benchmark) -> None:
|
||||
"""Discover functions across 10 source files."""
|
||||
benchmark(_discover_all)
|
||||
|
||||
|
||||
def test_benchmark_extract_context_multi_file(benchmark) -> None:
|
||||
"""Extract code optimization context for 10 functions across 10 files."""
|
||||
benchmark(_extract_all_contexts)
|
||||
56
.codeflash/benchmarks/test_benchmark_libcst_pipeline.py
Normal file
56
.codeflash/benchmarks/test_benchmark_libcst_pipeline.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""Benchmark the full libcst-heavy pipeline on a single file.
|
||||
|
||||
Runs discover → extract context → replace functions → add global assignments
|
||||
in sequence, exercising ~15 distinct visitor/transformer classes in one pass.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
|
||||
from codeflash.languages.python.context.code_context_extractor import get_code_optimization_context
|
||||
from codeflash.languages.python.static_analysis.code_extractor import add_global_assignments
|
||||
from codeflash.languages.python.static_analysis.code_replacer import replace_functions_in_file
|
||||
from codeflash.languages.python.support import PythonSupport
|
||||
|
||||
_CODEFLASH_ROOT = Path(__file__).parent.parent.parent.resolve() / "codeflash"
|
||||
_PROJECT_ROOT = _CODEFLASH_ROOT.parent
|
||||
|
||||
# Target: a real, non-trivial file with classes and module-level functions.
|
||||
_TARGET_FILE = _CODEFLASH_ROOT / "languages" / "python" / "static_analysis" / "code_extractor.py"
|
||||
_TARGET_FUNC = "add_global_assignments"
|
||||
|
||||
# A second file to serve as "optimized" source for replace/merge steps.
|
||||
_SECOND_FILE = _CODEFLASH_ROOT / "languages" / "python" / "static_analysis" / "code_replacer.py"
|
||||
|
||||
|
||||
def _run_pipeline() -> None:
|
||||
"""Simulate a single-file optimization pass through the full visitor pipeline."""
|
||||
source = _TARGET_FILE.read_text(encoding="utf-8")
|
||||
source2 = _SECOND_FILE.read_text(encoding="utf-8")
|
||||
|
||||
# 1. Discover functions (FunctionVisitor + MetadataWrapper)
|
||||
ps = PythonSupport()
|
||||
functions = ps.discover_functions(source=source, file_path=_TARGET_FILE)
|
||||
|
||||
# 2. Extract code optimization context (multiple collectors + dependency resolver)
|
||||
fto = FunctionToOptimize(
|
||||
function_name=_TARGET_FUNC, file_path=_TARGET_FILE, parents=[], starting_line=None, ending_line=None
|
||||
)
|
||||
get_code_optimization_context(fto, _PROJECT_ROOT)
|
||||
|
||||
# 3. Replace functions (GlobalFunctionCollector + GlobalFunctionTransformer)
|
||||
# Use a class method from discovered functions if available, else module-level.
|
||||
func_names = [_TARGET_FUNC]
|
||||
replace_functions_in_file(
|
||||
source_code=source, original_function_names=func_names, optimized_code=source2, preexisting_objects=set()
|
||||
)
|
||||
|
||||
# 4. Add global assignments (6 visitors/transformers)
|
||||
add_global_assignments(source2, source)
|
||||
|
||||
|
||||
def test_benchmark_full_pipeline(benchmark) -> None:
|
||||
"""Full discover → extract → replace → merge pipeline on one file."""
|
||||
benchmark(_run_pipeline)
|
||||
|
|
@ -2,7 +2,7 @@ from codeflash.models.models import FunctionTestInvocation, InvocationId, TestRe
|
|||
from codeflash.verification.parse_test_output import merge_test_results
|
||||
|
||||
|
||||
def generate_test_invocations(count=100):
|
||||
def generate_test_invocations(count: int = 100) -> tuple[TestResults, TestResults]:
|
||||
"""Generate a set number of test invocations for benchmarking."""
|
||||
test_results_xml = TestResults()
|
||||
test_results_bin = TestResults()
|
||||
|
|
@ -21,7 +21,7 @@ def generate_test_invocations(count=100):
|
|||
function_getting_tested="sorter",
|
||||
iteration_id=iteration_id,
|
||||
),
|
||||
file_name="/tmp/tests/unittest/test_bubble_sort__perfinstrumented.py",
|
||||
file_name="/tmp/tests/unittest/test_bubble_sort__perfinstrumented.py", # noqa: S108
|
||||
did_pass=True,
|
||||
runtime=None if i % 3 == 0 else i * 100, # Vary runtime values
|
||||
test_framework="unittest",
|
||||
|
|
@ -42,7 +42,7 @@ def generate_test_invocations(count=100):
|
|||
function_getting_tested="sorter",
|
||||
iteration_id=iteration_id,
|
||||
),
|
||||
file_name="/tmp/tests/unittest/test_bubble_sort__perfinstrumented.py",
|
||||
file_name="/tmp/tests/unittest/test_bubble_sort__perfinstrumented.py", # noqa: S108
|
||||
did_pass=True,
|
||||
runtime=500 + i * 20, # Generate varying runtime values
|
||||
test_framework="unittest",
|
||||
|
|
@ -56,12 +56,12 @@ def generate_test_invocations(count=100):
|
|||
return test_results_xml, test_results_bin
|
||||
|
||||
|
||||
def run_merge_benchmark(count=100):
|
||||
def run_merge_benchmark(count: int = 100) -> None:
|
||||
test_results_xml, test_results_bin = generate_test_invocations(count)
|
||||
|
||||
# Perform the merge operation that will be benchmarked
|
||||
merge_test_results(xml_test_results=test_results_xml, bin_test_results=test_results_bin, test_framework="unittest")
|
||||
|
||||
|
||||
def test_benchmark_merge_test_results(benchmark):
|
||||
def test_benchmark_merge_test_results(benchmark) -> None:
|
||||
benchmark(run_merge_benchmark, 1000) # Default to 100 test invocations
|
||||
17
.coveragerc
Normal file
17
.coveragerc
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[run]
|
||||
branch = true
|
||||
source = codeflash
|
||||
omit =
|
||||
codeflash/version.py
|
||||
|
||||
[report]
|
||||
sort = cover
|
||||
show_missing = true
|
||||
fail_under = 58
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
if TYPE_CHECKING:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
[html]
|
||||
directory = htmlcov
|
||||
38
.github/CODEOWNERS
vendored
Normal file
38
.github/CODEOWNERS
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Default fallback
|
||||
* @KRRT7
|
||||
|
||||
# Java
|
||||
/codeflash/languages/java/ @mashraf-222 @HeshamHM28 @misrasaurabh1
|
||||
|
||||
# JavaScript / TypeScript
|
||||
/codeflash/languages/javascript/ @Saga4 @mohammedahmed18 @KRRT7
|
||||
|
||||
# Python language support
|
||||
/codeflash/languages/python/ @KRRT7
|
||||
|
||||
# Core pipeline
|
||||
/codeflash/optimization/ @KRRT7 @aseembits93 @misrasaurabh1
|
||||
/codeflash/verification/ @KRRT7 @misrasaurabh1
|
||||
/codeflash/benchmarking/ @KRRT7
|
||||
/codeflash/discovery/ @KRRT7 @misrasaurabh1
|
||||
|
||||
# CLI & setup
|
||||
/codeflash/cli_cmds/ @KRRT7 @misrasaurabh1
|
||||
|
||||
# LSP
|
||||
/codeflash/lsp/ @mohammedahmed18
|
||||
|
||||
# API
|
||||
/codeflash/api/ @KRRT7 @aseembits93
|
||||
|
||||
# Tracing & entry points
|
||||
/codeflash/tracing/ @misrasaurabh1 @KRRT7
|
||||
/codeflash/main.py @misrasaurabh1 @KRRT7
|
||||
/codeflash/tracer.py @misrasaurabh1 @KRRT7
|
||||
|
||||
# Shared utilities
|
||||
/codeflash/code_utils/ @KRRT7 @aseembits93 @misrasaurabh1
|
||||
/codeflash/models/ @KRRT7
|
||||
|
||||
# CI / workflows
|
||||
/.github/ @KRRT7
|
||||
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
## Linked issue or discussion
|
||||
|
||||
<!-- Every PR must link to an issue or discussion — this ensures the approach has been discussed with maintainers before implementation begins, so your work fits the project's direction and doesn't need to be reworked. -->
|
||||
<!-- Replace the line below with one of: -->
|
||||
<!-- Closes #<number> -->
|
||||
<!-- Fixes #<number> -->
|
||||
<!-- Relates to #<number> -->
|
||||
<!-- Discussion: <url> -->
|
||||
|
||||
**Required:** <!-- CI will fail if no linked issue or discussion is found. -->
|
||||
|
||||
## What changed
|
||||
|
||||
<!-- Brief description of the changes. -->
|
||||
|
||||
## Test plan
|
||||
|
||||
<!-- How was this tested? Link to passing CI, new tests, or manual verification steps. -->
|
||||
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
|
|
@ -1,4 +1,3 @@
|
|||
# TEMPORARILY DISABLED — re-enable by removing open-pull-requests-limit: 0
|
||||
version: 2
|
||||
updates:
|
||||
# Python (root pyproject.toml)
|
||||
|
|
@ -6,21 +5,21 @@ updates:
|
|||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 0
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
# JavaScript (codeflash npm package)
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/packages/codeflash"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 0
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
# GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 0
|
||||
open-pull-requests-limit: 5
|
||||
|
||||
# code_to_optimize/ directories are test fixtures — do NOT update them.
|
||||
# Dependabot PRs for these always fail (missing secrets) and waste CI.
|
||||
# Their package-lock.json files are gitignored to prevent Dependabot alerts.
|
||||
|
|
|
|||
267
.github/workflows/ci.yaml
vendored
267
.github/workflows/ci.yaml
vendored
|
|
@ -23,88 +23,86 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
# ---------------------------------------------------------------------------
|
||||
# Change detection — decides which downstream jobs actually run.
|
||||
# On push/workflow_dispatch every flag is true so all jobs execute.
|
||||
# On pull_request we diff against the merge base (same approach as astral-sh/ruff).
|
||||
# Linked issue check — every PR must reference an issue or discussion.
|
||||
# Skipped on push to main and workflow_dispatch.
|
||||
# ---------------------------------------------------------------------------
|
||||
determine-changes:
|
||||
check-linked-issue:
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
unit_tests: ${{ github.event_name != 'pull_request' || steps.check.outputs.unit_tests == 'true' }}
|
||||
type_check: ${{ github.event_name != 'pull_request' || steps.check.outputs.type_check == 'true' }}
|
||||
e2e: ${{ github.event_name != 'pull_request' || steps.check.outputs.e2e == 'true' }}
|
||||
e2e_js: ${{ github.event_name != 'pull_request' || steps.check.outputs.e2e_js == 'true' }}
|
||||
e2e_java: ${{ github.event_name != 'pull_request' || steps.check.outputs.e2e_java == 'true' }}
|
||||
pull-requests: read
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Determine merge base
|
||||
if: github.event_name == 'pull_request'
|
||||
id: merge_base
|
||||
run: |
|
||||
sha=$(git merge-base HEAD "origin/${{ github.event.pull_request.base.ref }}")
|
||||
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check changed paths
|
||||
if: github.event_name == 'pull_request'
|
||||
id: check
|
||||
run: |
|
||||
check_paths() {
|
||||
local name="$1"; shift
|
||||
if ! git diff --quiet "$MERGE_BASE...HEAD" -- "$@" 2>/dev/null; then
|
||||
echo "${name}=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "${name}=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
}
|
||||
|
||||
# Unit tests: code + test infra + packages + build config
|
||||
check_paths unit_tests \
|
||||
'codeflash/' 'codeflash-benchmark/' \
|
||||
'tests/' 'packages/' 'pyproject.toml' 'uv.lock'
|
||||
|
||||
# Type checking: code + build config + mypy config
|
||||
check_paths type_check \
|
||||
'codeflash/' 'pyproject.toml' 'uv.lock' 'mypy_allowlist.txt'
|
||||
|
||||
# E2E tests: Python pipeline + tests + build config (excludes java/ and javascript/)
|
||||
check_paths e2e \
|
||||
'codeflash/*.py' \
|
||||
'codeflash/api/' 'codeflash/benchmarking/' 'codeflash/cli_cmds/' \
|
||||
'codeflash/code_utils/' 'codeflash/discovery/' 'codeflash/github/' \
|
||||
'codeflash/languages/python/' 'codeflash/languages/*.py' \
|
||||
'codeflash/lsp/' 'codeflash/models/' 'codeflash/optimization/' \
|
||||
'codeflash/picklepatch/' 'codeflash/result/' 'codeflash/setup/' \
|
||||
'codeflash/telemetry/' 'codeflash/tracing/' 'codeflash/verification/' \
|
||||
'tests/' 'pyproject.toml' 'uv.lock'
|
||||
|
||||
# JS E2E tests: JS language support + shared pipeline + packages + test fixtures
|
||||
check_paths e2e_js \
|
||||
'codeflash/languages/javascript/' 'codeflash/languages/base.py' \
|
||||
'codeflash/languages/registry.py' 'codeflash/optimization/' \
|
||||
'codeflash/verification/' 'packages/' \
|
||||
'code_to_optimize/js/' 'tests/scripts/end_to_end_test_js*'
|
||||
|
||||
# Java E2E tests: Java language support + shared pipeline + runtime
|
||||
check_paths e2e_java \
|
||||
'codeflash/languages/java/' 'codeflash/languages/base.py' \
|
||||
'codeflash/languages/registry.py' 'codeflash/optimization/' \
|
||||
'codeflash/verification/' 'codeflash-java-runtime/' \
|
||||
'code_to_optimize/java/' 'tests/scripts/end_to_end_test_java*'
|
||||
- name: Check PR body for linked issue or discussion
|
||||
env:
|
||||
MERGE_BASE: ${{ steps.merge_base.outputs.sha }}
|
||||
PR_BODY: ${{ github.event.pull_request.body }}
|
||||
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
||||
AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
|
||||
run: |
|
||||
# Skip for bots (dependabot, renovate, github-actions)
|
||||
if [[ "$PR_AUTHOR" == *"[bot]"* || "$PR_AUTHOR" == "dependabot" ]]; then
|
||||
echo "Bot PR — skipping linked issue check."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Skip for org members and collaborators
|
||||
if [[ "$AUTHOR_ASSOCIATION" == "MEMBER" || "$AUTHOR_ASSOCIATION" == "COLLABORATOR" || "$AUTHOR_ASSOCIATION" == "OWNER" ]]; then
|
||||
echo "Org member ($PR_AUTHOR, $AUTHOR_ASSOCIATION) — skipping linked issue check."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$PR_BODY" ]; then
|
||||
echo "::error::PR body is empty. Every PR must link an issue or discussion."
|
||||
echo "Use 'Closes #<number>', 'Fixes #<number>', 'Relates to #<number>', or include a discussion URL."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Match: #123, GH-123, org/repo#123, Closes/Fixes/Relates/Resolves #123,
|
||||
# or a github.com URL to an issue or discussion
|
||||
if echo "$PR_BODY" | grep -qiP '(close[sd]?|fix(e[sd])?|relate[sd]?\s+to|resolve[sd]?)\s+#\d+'; then
|
||||
echo "Found linked issue keyword."
|
||||
exit 0
|
||||
fi
|
||||
if echo "$PR_BODY" | grep -qP '#\d+'; then
|
||||
echo "Found issue reference."
|
||||
exit 0
|
||||
fi
|
||||
if echo "$PR_BODY" | grep -qiP 'github\.com/[^\s]+/(issues|discussions)/\d+'; then
|
||||
echo "Found GitHub issue/discussion URL."
|
||||
exit 0
|
||||
fi
|
||||
if echo "$PR_BODY" | grep -qiP 'CF-#?\d+'; then
|
||||
echo "Found Linear ticket reference."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "::error::No linked issue or discussion found in PR body."
|
||||
echo "Every PR must reference an issue or discussion. See CONTRIBUTING.md for details."
|
||||
echo "Use 'Closes #<number>', 'Fixes #<number>', 'Relates to #<number>', or include a discussion URL."
|
||||
exit 1
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Change detection — decides which downstream jobs actually run.
|
||||
# On push/workflow_dispatch every flag is true so all jobs execute.
|
||||
# On pull_request we diff against the merge base.
|
||||
# ---------------------------------------------------------------------------
|
||||
determine-changes:
|
||||
uses: codeflash-ai/github-workflows/.github/workflows/determine-changes.yml@main
|
||||
with:
|
||||
path-filters: |
|
||||
{
|
||||
"unit_tests": ["codeflash/", "codeflash-benchmark/", "tests/", "packages/", "pyproject.toml", "uv.lock"],
|
||||
"type_check": ["codeflash/", "pyproject.toml", "uv.lock", "mypy_allowlist.txt"],
|
||||
"e2e": ["codeflash/*.py", "codeflash/api/", "codeflash/benchmarking/", "codeflash/cli_cmds/", "codeflash/code_utils/", "codeflash/discovery/", "codeflash/github/", "codeflash/languages/python/", "codeflash/languages/*.py", "codeflash/lsp/", "codeflash/models/", "codeflash/optimization/", "codeflash/picklepatch/", "codeflash/result/", "codeflash/setup/", "codeflash/telemetry/", "codeflash/tracing/", "codeflash/verification/", "tests/", "pyproject.toml", "uv.lock"],
|
||||
"e2e_js": ["codeflash/languages/javascript/", "codeflash/languages/base.py", "codeflash/languages/registry.py", "codeflash/optimization/", "codeflash/verification/", "packages/", "code_to_optimize/js/", "tests/scripts/end_to_end_test_js*"],
|
||||
"e2e_java": ["codeflash/languages/java/", "codeflash/languages/base.py", "codeflash/languages/registry.py", "codeflash/optimization/", "codeflash/verification/", "codeflash-java-runtime/", "code_to_optimize/java/", "tests/scripts/end_to_end_test_java*", "tests/test_languages/fixtures/java_tracer_e2e/"]
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unit tests — 6 Linux + 1 Windows matrix
|
||||
# ---------------------------------------------------------------------------
|
||||
unit-tests:
|
||||
needs: determine-changes
|
||||
if: needs.determine-changes.outputs.unit_tests == 'true'
|
||||
if: fromJSON(needs.determine-changes.outputs.flags).unit_tests == 'true'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -133,7 +131,7 @@ jobs:
|
|||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
enable-cache: true
|
||||
|
|
@ -150,12 +148,50 @@ jobs:
|
|||
- name: Unit tests
|
||||
run: uv run pytest tests/
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Coverage — single run on ubuntu/py3.13 to enforce the coverage floor.
|
||||
# ---------------------------------------------------------------------------
|
||||
coverage:
|
||||
needs: determine-changes
|
||||
if: fromJSON(needs.determine-changes.outputs.flags).unit_tests == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PYTHONIOENCODING: utf-8
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
enable-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: uv run pytest tests/ --ignore=tests/test_tracer.py --cov=codeflash --cov-report=xml:coverage.xml --cov-report=term-missing --cov-config=.coveragerc
|
||||
|
||||
- name: Check coverage floor
|
||||
run: uv run coverage report --fail-under=58
|
||||
|
||||
- name: Upload coverage report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverage-report
|
||||
path: coverage.xml
|
||||
retention-days: 30
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mypy type checking
|
||||
# ---------------------------------------------------------------------------
|
||||
type-check:
|
||||
needs: determine-changes
|
||||
if: needs.determine-changes.outputs.type_check == 'true'
|
||||
if: fromJSON(needs.determine-changes.outputs.flags).type_check == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
|
@ -164,7 +200,7 @@ jobs:
|
|||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
|
|
@ -181,37 +217,15 @@ jobs:
|
|||
needs: determine-changes
|
||||
if: >-
|
||||
github.event_name == 'pull_request'
|
||||
&& (needs.determine-changes.outputs.e2e == 'true'
|
||||
|| needs.determine-changes.outputs.e2e_js == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
&& (fromJSON(needs.determine-changes.outputs.flags).e2e == 'true'
|
||||
|| fromJSON(needs.determine-changes.outputs.flags).e2e_js == 'true')
|
||||
uses: codeflash-ai/github-workflows/.github/workflows/prek-lint.yml@main
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
fetch-depth: 0
|
||||
- uses: astral-sh/setup-uv@v8.0.0
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
- name: Auto-fix formatting
|
||||
run: |
|
||||
uv run ruff check --fix . || true
|
||||
uv run ruff format .
|
||||
|
||||
- name: Commit and push fixes
|
||||
run: |
|
||||
git diff --quiet && exit 0
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add -u
|
||||
git commit -m "style: auto-format with ruff"
|
||||
git push
|
||||
|
||||
- uses: j178/prek-action@v2
|
||||
with:
|
||||
extra-args: '--from-ref origin/${{ github.base_ref }} --to-ref HEAD'
|
||||
with:
|
||||
auto-fix: true
|
||||
checkout-ref: ${{ github.head_ref }}
|
||||
restore-paths: "codeflash/version.py codeflash-benchmark/codeflash_benchmark/version.py"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# E2E tests — only on pull_request and workflow_dispatch (not push to main)
|
||||
|
|
@ -221,8 +235,9 @@ jobs:
|
|||
e2e-python:
|
||||
needs: determine-changes
|
||||
if: >-
|
||||
needs.determine-changes.outputs.e2e == 'true'
|
||||
fromJSON(needs.determine-changes.outputs.flags).e2e == 'true'
|
||||
&& github.event_name != 'push'
|
||||
&& github.actor != 'dependabot[bot]'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -255,7 +270,7 @@ jobs:
|
|||
- name: init-optimization
|
||||
script: end_to_end_test_init_optimization.py
|
||||
expected_improvement: 10
|
||||
environment: ${{ (github.event_name == 'workflow_dispatch' || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
environment: ${{ ((github.event_name == 'workflow_dispatch' && github.actor != 'misrasaurabh1' && github.actor != 'KRRT7') || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEFLASH_AIS_SERVER: prod
|
||||
|
|
@ -282,7 +297,7 @@ jobs:
|
|||
pr_state: ${{ github.event.pull_request.state }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: 3.11.6
|
||||
enable-cache: true
|
||||
|
|
@ -324,8 +339,9 @@ jobs:
|
|||
e2e-js:
|
||||
needs: determine-changes
|
||||
if: >-
|
||||
needs.determine-changes.outputs.e2e_js == 'true'
|
||||
fromJSON(needs.determine-changes.outputs.flags).e2e_js == 'true'
|
||||
&& github.event_name != 'push'
|
||||
&& github.actor != 'dependabot[bot]'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -338,11 +354,13 @@ jobs:
|
|||
script: end_to_end_test_js_esm_async.py
|
||||
js_project_dir: code_to_optimize/js/code_to_optimize_js_esm
|
||||
expected_improvement: 10
|
||||
allow_failure: true
|
||||
- name: js-ts-class
|
||||
script: end_to_end_test_js_ts_class.py
|
||||
js_project_dir: code_to_optimize/js/code_to_optimize_ts
|
||||
expected_improvement: 30
|
||||
environment: ${{ (github.event_name == 'workflow_dispatch' || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
continue-on-error: ${{ matrix.allow_failure || false }}
|
||||
environment: ${{ ((github.event_name == 'workflow_dispatch' && github.actor != 'misrasaurabh1' && github.actor != 'KRRT7') || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEFLASH_AIS_SERVER: prod
|
||||
|
|
@ -390,7 +408,7 @@ jobs:
|
|||
npm install
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: 3.11.6
|
||||
enable-cache: true
|
||||
|
|
@ -405,8 +423,9 @@ jobs:
|
|||
e2e-java:
|
||||
needs: determine-changes
|
||||
if: >-
|
||||
needs.determine-changes.outputs.e2e_java == 'true'
|
||||
fromJSON(needs.determine-changes.outputs.flags).e2e_java == 'true'
|
||||
&& github.event_name != 'push'
|
||||
&& github.actor != 'dependabot[bot]'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
|
@ -422,7 +441,7 @@ jobs:
|
|||
script: end_to_end_test_java_void_optimization.py
|
||||
expected_improvement: 70
|
||||
remove_git: true
|
||||
environment: ${{ (github.event_name == 'workflow_dispatch' || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
environment: ${{ ((github.event_name == 'workflow_dispatch' && github.actor != 'misrasaurabh1' && github.actor != 'KRRT7') || (contains(toJSON(github.event.pull_request.files.*.filename), '.github/workflows/') && github.event.pull_request.user.login != 'misrasaurabh1' && github.event.pull_request.user.login != 'KRRT7')) && 'external-trusted-contributors' || '' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEFLASH_AIS_SERVER: prod
|
||||
|
|
@ -433,6 +452,7 @@ jobs:
|
|||
RETRY_DELAY: 5
|
||||
EXPECTED_IMPROVEMENT_PCT: ${{ matrix.expected_improvement }}
|
||||
CODEFLASH_END_TO_END: 1
|
||||
CODEFLASH_LOOPING_TIME: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
|
|
@ -458,7 +478,7 @@ jobs:
|
|||
cache: maven
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: 3.11.6
|
||||
enable-cache: true
|
||||
|
|
@ -466,7 +486,15 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Cache codeflash-runtime JAR
|
||||
id: runtime-jar-cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.m2/repository/io/codeflash
|
||||
key: codeflash-runtime-${{ hashFiles('codeflash-java-runtime/pom.xml', 'codeflash-java-runtime/src/**') }}
|
||||
|
||||
- name: Build and install codeflash-runtime JAR
|
||||
if: steps.runtime-jar-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd codeflash-java-runtime
|
||||
mvn install -q -DskipTests
|
||||
|
|
@ -494,7 +522,9 @@ jobs:
|
|||
name: required checks passed
|
||||
if: always()
|
||||
needs:
|
||||
- check-linked-issue
|
||||
- unit-tests
|
||||
- coverage
|
||||
- type-check
|
||||
- prek
|
||||
- e2e-python
|
||||
|
|
@ -502,13 +532,6 @@ jobs:
|
|||
- e2e-java
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Verify all required jobs passed
|
||||
run: |
|
||||
failing=$(echo "$NEEDS_JSON" | jq -r 'to_entries[] | select(.value.result != "success" and .value.result != "skipped") | "\(.key): \(.value.result)"')
|
||||
if [ -n "$failing" ]; then
|
||||
echo "Required jobs failed or were cancelled:"
|
||||
echo "$failing"
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
NEEDS_JSON: ${{ toJSON(needs) }}
|
||||
- uses: codeflash-ai/github-workflows/.github/actions/required-checks-gate@main
|
||||
with:
|
||||
needs-json: ${{ toJSON(needs) }}
|
||||
|
|
|
|||
4
.github/workflows/claude.yml
vendored
4
.github/workflows/claude.yml
vendored
|
|
@ -57,7 +57,7 @@ jobs:
|
|||
ref: ${{ github.event.pull_request.head.ref || github.ref }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
|
|
@ -319,7 +319,7 @@ jobs:
|
|||
ref: ${{ steps.pr-ref.outputs.ref }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
|
|
|
|||
4
.github/workflows/codeflash-optimize.yaml
vendored
4
.github/workflows/codeflash-optimize.yaml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
|
||||
- name: 🐍 Set up Python 3.11 for CLI
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: 3.11.6
|
||||
enable-cache: true
|
||||
|
|
@ -43,4 +43,4 @@ jobs:
|
|||
- name: ⚡️Codeflash Optimization
|
||||
id: optimize_code
|
||||
run: |
|
||||
uv run codeflash --benchmark --testgen-review
|
||||
uv run codeflash --benchmark --testgen-review --no-pr
|
||||
42
.github/workflows/codeflash.yaml
vendored
42
.github/workflows/codeflash.yaml
vendored
|
|
@ -1,42 +0,0 @@
|
|||
name: Codeflash
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
# So that this workflow only runs when code within the target module is modified
|
||||
- 'code_to_optimize/js/code_to_optimize_js_esm/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
# Any new push to the PR will cancel the previous run, so that only the latest code is optimized
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
|
||||
jobs:
|
||||
optimize:
|
||||
name: Optimize new code
|
||||
# Don't run codeflash on codeflash-ai[bot] commits, prevent duplicate optimizations
|
||||
if: ${{ github.actor != 'codeflash-ai[bot]' }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEFLASH_API_KEY: ${{ secrets.CODEFLASH_API_KEY }}
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./code_to_optimize/js/code_to_optimize_js_esm
|
||||
steps:
|
||||
- name: 🛎️ Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: 🟢 Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: code_to_optimize/js/code_to_optimize_js_esm/package-lock.json
|
||||
- name: 📦 Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: ⚡️ Codeflash Optimization
|
||||
run: npx codeflash
|
||||
77
.github/workflows/java-e2e.yaml
vendored
Normal file
77
.github/workflows/java-e2e.yaml
vendored
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
name: Java E2E Tests
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
e2e-java:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: java-fibonacci-nogit
|
||||
script: end_to_end_test_java_fibonacci.py
|
||||
expected_improvement: 70
|
||||
remove_git: true
|
||||
- name: java-tracer
|
||||
script: end_to_end_test_java_tracer.py
|
||||
expected_improvement: 10
|
||||
- name: java-void-optimization-nogit
|
||||
script: end_to_end_test_java_void_optimization.py
|
||||
expected_improvement: 70
|
||||
remove_git: true
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CODEFLASH_AIS_SERVER: prod
|
||||
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
|
||||
CODEFLASH_API_KEY: ${{ secrets.CODEFLASH_API_KEY }}
|
||||
COLUMNS: 110
|
||||
MAX_RETRIES: 3
|
||||
RETRY_DELAY: 5
|
||||
EXPECTED_IMPROVEMENT_PCT: ${{ matrix.expected_improvement }}
|
||||
CODEFLASH_END_TO_END: 1
|
||||
CODEFLASH_LOOPING_TIME: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
cache: maven
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
python-version: 3.11.6
|
||||
enable-cache: true
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Cache codeflash-runtime JAR
|
||||
id: runtime-jar-cache
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.m2/repository/io/codeflash
|
||||
key: codeflash-runtime-${{ hashFiles('codeflash-java-runtime/pom.xml', 'codeflash-java-runtime/src/**') }}
|
||||
|
||||
- name: Build and install codeflash-runtime JAR
|
||||
if: steps.runtime-jar-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd codeflash-java-runtime
|
||||
mvn install -q -DskipTests
|
||||
|
||||
- name: Remove .git
|
||||
if: matrix.remove_git
|
||||
run: |
|
||||
if [ -d ".git" ]; then
|
||||
sudo rm -rf .git
|
||||
echo ".git directory removed."
|
||||
else
|
||||
echo ".git directory does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Run E2E test
|
||||
run: uv run python tests/scripts/${{ matrix.script }}
|
||||
2
.github/workflows/label-workflow-changes.yml
vendored
2
.github/workflows/label-workflow-changes.yml
vendored
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
pull-requests: write
|
||||
steps:
|
||||
- name: Label PR with workflow changes
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v9
|
||||
with:
|
||||
script: |
|
||||
const labelName = 'workflow-modified';
|
||||
|
|
|
|||
4
.github/workflows/publish.yml
vendored
4
.github/workflows/publish.yml
vendored
|
|
@ -110,7 +110,7 @@ jobs:
|
|||
|
||||
- name: Install uv
|
||||
if: steps.should_run.outputs.run == 'true' && steps.check_tag.outputs.exists == 'false'
|
||||
uses: astral-sh/setup-uv@v8.0.0
|
||||
uses: astral-sh/setup-uv@v8.1.0
|
||||
with:
|
||||
enable-cache: true
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ jobs:
|
|||
|
||||
- name: Create GitHub Release
|
||||
if: steps.should_run.outputs.run == 'true' && steps.check_tag.outputs.exists == 'false'
|
||||
uses: softprops/action-gh-release@v2
|
||||
uses: softprops/action-gh-release@v3
|
||||
with:
|
||||
tag_name: ${{ steps.extract_version.outputs.tag }}
|
||||
name: ${{ matrix.release_name_prefix }} ${{ steps.extract_version.outputs.tag }}
|
||||
|
|
|
|||
8
.github/workflows/ready-to-merge.yml
vendored
Normal file
8
.github/workflows/ready-to-merge.yml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
name: Ready to Merge
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
ready:
|
||||
uses: codeflash-ai/github-workflows/.github/workflows/ready-to-merge.yml@main
|
||||
18
.github/workflows/tessl-update.yml
vendored
Normal file
18
.github/workflows/tessl-update.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
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:
|
||||
tessl:
|
||||
uses: codeflash-ai/github-workflows/.github/workflows/tessl-update.yml@main
|
||||
secrets:
|
||||
TESSL_TOKEN: ${{ secrets.TESSL_TOKEN }}
|
||||
CI_BOT_APP_ID: ${{ secrets.CI_BOT_APP_ID }}
|
||||
CI_BOT_PRIVATE_KEY: ${{ secrets.CI_BOT_PRIVATE_KEY }}
|
||||
358
.gitignore
vendored
358
.gitignore
vendored
|
|
@ -1,7 +1,10 @@
|
|||
# =============================================================================
|
||||
# Python — https://github.com/github/gitignore/blob/main/Python.gitignore
|
||||
# =============================================================================
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
**/__pycache__/
|
||||
*.py[cod]
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
|
|
@ -10,9 +13,8 @@ __pycache__/
|
|||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
.gradle/
|
||||
develop-eggs/
|
||||
cli/dist/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
|
|
@ -33,7 +35,6 @@ MANIFEST
|
|||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
*.pyc
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
|
@ -49,7 +50,7 @@ htmlcov/
|
|||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
*.py.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
|
@ -97,20 +98,35 @@ ipython_config.py
|
|||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
#poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
#pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
#pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
|
@ -124,7 +140,7 @@ celerybeat.pid
|
|||
|
||||
# Environments
|
||||
.env
|
||||
**/.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
|
|
@ -162,120 +178,254 @@ cython_debug/
|
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.aider*
|
||||
/js/common/node_modules/
|
||||
*.xml
|
||||
# Allow pom.xml in test fixtures for Maven project detection
|
||||
!tests/test_languages/fixtures/**/pom.xml
|
||||
# Allow pom.xml in Java sample project
|
||||
!code_to_optimize/java/pom.xml
|
||||
# Allow pom.xml in codeflash-java-runtime
|
||||
!codeflash-java-runtime/pom.xml
|
||||
*.pem
|
||||
|
||||
# Ruff cache
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# IDE settings
|
||||
.idea/
|
||||
.vscode/
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
# Cursor
|
||||
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
|
||||
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
|
||||
# refer to https://docs.cursor.com/context/ignore-files
|
||||
.cursorignore
|
||||
.cursorindexingignore
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
# =============================================================================
|
||||
# Node — https://github.com/github/gitignore/blob/main/Node.gitignore
|
||||
# =============================================================================
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
# Logs
|
||||
logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Sveltekit cache directory
|
||||
.svelte-kit/
|
||||
|
||||
# vitepress build output
|
||||
**/.vitepress/dist
|
||||
|
||||
# vitepress cache directory
|
||||
**/.vitepress/cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# Firebase cache directory
|
||||
.firebase/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v3
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
# Vite logs files
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# =============================================================================
|
||||
# Java — https://github.com/github/gitignore/blob/main/Java.gitignore
|
||||
# =============================================================================
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# =============================================================================
|
||||
# Project-specific
|
||||
# =============================================================================
|
||||
|
||||
# XML (Maven generates many; allow specific pom.xml files)
|
||||
*.xml
|
||||
!tests/test_languages/fixtures/**/pom.xml
|
||||
!code_to_optimize/java/pom.xml
|
||||
!codeflash-java-runtime/pom.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
.gradle/
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
# Credentials
|
||||
*.pem
|
||||
**/.env
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
# IDEs
|
||||
.idea/
|
||||
.vscode/*
|
||||
!.vscode/mcp.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
# Nuitka
|
||||
**/dist-nuitka/**
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
# npm
|
||||
**/.npmrc
|
||||
|
||||
# Mac
|
||||
.DS_Store
|
||||
WARP.MD
|
||||
|
||||
.mcp.json
|
||||
.tessl/
|
||||
tessl.json
|
||||
# Playwright MCP
|
||||
.playwright-mcp/
|
||||
|
||||
# Claude Code - track shared rules, ignore local config
|
||||
# Tessl — .tessl/.gitignore handles tiles/RULES.md internally
|
||||
.tessl/session-data/
|
||||
|
||||
# Claude Code — track shared config, ignore local state
|
||||
.claude/*
|
||||
!.claude/rules/
|
||||
!.claude/settings.json
|
||||
!.claude/hooks/
|
||||
**/node_modules/**
|
||||
**/dist-nuitka/**
|
||||
**/.npmrc
|
||||
!.claude/skills/
|
||||
!.claude/settings.json
|
||||
|
||||
# Tessl auto-generates AGENTS.md on install; ignore to avoid cluttering git status
|
||||
AGENTS.md
|
||||
.serena/
|
||||
# Test fixture lockfiles — prevents Dependabot from scanning them
|
||||
code_to_optimize/**/package-lock.json
|
||||
|
||||
# Other tools
|
||||
.codeflash/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,15 @@
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.15.8
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff-check
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.15.8
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
- id: ruff-format
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy
|
||||
entry: uv run mypy --non-interactive --config-file pyproject.toml
|
||||
language: system
|
||||
types: [python]
|
||||
require_serial: true
|
||||
|
|
|
|||
24
.tessl/missing-tiles.txt
Normal file
24
.tessl/missing-tiles.txt
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# PyPI
|
||||
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
|
||||
# npm
|
||||
tessl/npm-msgpack--msgpack
|
||||
tessl/npm-babel--register
|
||||
tessl/npm-babel--preset-env
|
||||
# Maven
|
||||
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
|
||||
|
|
@ -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<String> 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<Date> {
|
||||
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<Color> {
|
||||
@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<String>, JsonDeserializer<String> {
|
||||
@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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
Class<T> rawType = (Class<T>) type.getRawType();
|
||||
if (!rawType.isEnum()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
@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<Enum>) 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;
|
||||
}
|
||||
```
|
||||
|
|
@ -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 extends Annotation> T getAnnotation(Class<T> annotation);
|
||||
public Collection<Annotation> 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();
|
||||
```
|
||||
|
|
@ -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
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.13.1</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 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> T fromJson(String json, Class<T> classOfT);
|
||||
public <T> T fromJson(String json, Type typeOfT);
|
||||
public <T> T fromJson(String json, TypeToken<T> 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> T fromJson(JsonElement json, Class<T> 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<T> {
|
||||
public abstract void write(JsonWriter out, T value) throws IOException;
|
||||
public abstract T read(JsonReader in) throws IOException;
|
||||
}
|
||||
|
||||
public interface TypeAdapterFactory {
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> 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<T> {
|
||||
public static <T> TypeToken<T> get(Class<T> type);
|
||||
public static TypeToken<?> get(Type type);
|
||||
public Type getType();
|
||||
}
|
||||
```
|
||||
|
|
@ -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<Map.Entry<String, JsonElement>> entrySet();
|
||||
public Set<String> 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<JsonElement> 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> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException;
|
||||
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException;
|
||||
public <T> T fromJson(JsonElement json, TypeToken<T> 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<JsonElement> {
|
||||
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<String, JsonElement> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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<String> names = Arrays.asList("Alice", "Bob", "Charlie");
|
||||
Type listType = new TypeToken<List<String>>(){}.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> T fromJson(String json, Class<T> 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> T fromJson(String json, Type typeOfT) throws JsonSyntaxException;
|
||||
public <T> T fromJson(String json, TypeToken<T> 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<List<String>>(){}.getType();
|
||||
List<String> names = gson.fromJson(json, listType);
|
||||
|
||||
// Or using TypeToken directly
|
||||
TypeToken<List<String>> token = new TypeToken<List<String>>(){};
|
||||
List<String> names = gson.fromJson(json, token);
|
||||
```
|
||||
|
||||
### Deserialization from Reader
|
||||
|
||||
```java { .api }
|
||||
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonIOException, JsonSyntaxException;
|
||||
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException;
|
||||
public <T> T fromJson(Reader json, TypeToken<T> 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> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException;
|
||||
public <T> T fromJson(JsonReader reader, TypeToken<T> 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<String> list = Arrays.asList("a", "b", "c");
|
||||
String json = gson.toJson(list);
|
||||
List<String> restored = gson.fromJson(json, new TypeToken<List<String>>(){}.getType());
|
||||
|
||||
// Maps
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
map.put("one", 1);
|
||||
map.put("two", 2);
|
||||
String json = gson.toJson(map);
|
||||
Map<String, Integer> restored = gson.fromJson(json, new TypeToken<Map<String, Integer>>(){}.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());
|
||||
}
|
||||
```
|
||||
|
|
@ -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<Person> {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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<T> {
|
||||
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<T> nullSafe();
|
||||
}
|
||||
```
|
||||
|
||||
## Creating Custom Type Adapters
|
||||
|
||||
**Basic type adapter example:**
|
||||
```java
|
||||
public class PersonAdapter extends TypeAdapter<Person> {
|
||||
@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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type);
|
||||
}
|
||||
```
|
||||
|
||||
**Example factory for enum handling:**
|
||||
```java
|
||||
public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
Class<T> rawType = (Class<T>) type.getRawType();
|
||||
if (!rawType.isEnum()) {
|
||||
return null; // This factory only handles enums
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
@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<Enum>) 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> CLASS;
|
||||
public static final TypeAdapter<Boolean> BOOLEAN;
|
||||
public static final TypeAdapter<Boolean> BOOLEAN_AS_STRING;
|
||||
public static final TypeAdapter<Number> BYTE;
|
||||
public static final TypeAdapter<Number> SHORT;
|
||||
public static final TypeAdapter<Number> INTEGER;
|
||||
public static final TypeAdapter<AtomicInteger> ATOMIC_INTEGER;
|
||||
public static final TypeAdapter<AtomicBoolean> ATOMIC_BOOLEAN;
|
||||
public static final TypeAdapter<Number> LONG;
|
||||
public static final TypeAdapter<Number> FLOAT;
|
||||
public static final TypeAdapter<Number> DOUBLE;
|
||||
public static final TypeAdapter<Character> CHARACTER;
|
||||
public static final TypeAdapter<String> STRING;
|
||||
public static final TypeAdapter<StringBuilder> STRING_BUILDER;
|
||||
public static final TypeAdapter<StringBuffer> STRING_BUFFER;
|
||||
public static final TypeAdapter<URL> URL;
|
||||
public static final TypeAdapter<URI> URI;
|
||||
public static final TypeAdapter<UUID> UUID;
|
||||
public static final TypeAdapter<Currency> CURRENCY;
|
||||
public static final TypeAdapter<Calendar> CALENDAR;
|
||||
public static final TypeAdapter<Locale> LOCALE;
|
||||
public static final TypeAdapter<JsonElement> JSON_ELEMENT;
|
||||
|
||||
// Factory methods
|
||||
public static <TT> TypeAdapterFactory newFactory(Class<TT> type, TypeAdapter<TT> typeAdapter);
|
||||
public static <TT> TypeAdapterFactory newFactory(TypeToken<TT> type, TypeAdapter<TT> 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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> 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<T>) new TypeAdapter<List<?>>() {
|
||||
@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<Object> 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<Date> {
|
||||
private final TypeAdapter<Date> delegate;
|
||||
|
||||
public TimestampAdapter(TypeAdapter<Date> 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<Animal>, JsonDeserializer<Animal> {
|
||||
@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<String> {
|
||||
@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<String> 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 <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
||||
TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
@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<T> {
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context);
|
||||
}
|
||||
|
||||
public interface JsonDeserializer<T> {
|
||||
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> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```java
|
||||
public class PersonSerializer implements JsonSerializer<Person> {
|
||||
@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();
|
||||
```
|
||||
|
|
@ -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."
|
||||
}
|
||||
|
|
@ -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
|
||||
<dependency>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>org.jacoco.agent</artifactId>
|
||||
<version>0.8.13</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 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
|
||||
```
|
||||
|
|
@ -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."
|
||||
}
|
||||
|
|
@ -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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> messageSupplier);
|
||||
|
||||
/**
|
||||
* Assert that lines match with pattern support
|
||||
*/
|
||||
static void assertLinesMatch(List<String> expectedLines, List<String> actualLines);
|
||||
static void assertLinesMatch(List<String> expectedLines, List<String> actualLines, String message);
|
||||
static void assertLinesMatch(List<String> expectedLines, List<String> actualLines, Supplier<String> messageSupplier);
|
||||
static void assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines);
|
||||
static void assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines, String message);
|
||||
static void assertLinesMatch(Stream<String> expectedLines, Stream<String> actualLines, Supplier<String> 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<String> expected = Arrays.asList("a", "b", "c");
|
||||
List<String> actual = Arrays.asList("a", "b", "c");
|
||||
assertIterableEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLinesMatch() {
|
||||
List<String> expected = Arrays.asList("Hello.*", "\\d+", "End");
|
||||
List<String> 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 extends Throwable> T assertThrows(Class<T> expectedType, Executable executable);
|
||||
static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, String message);
|
||||
static <T extends Throwable> T assertThrows(Class<T> expectedType, Executable executable, Supplier<String> messageSupplier);
|
||||
|
||||
/**
|
||||
* Assert that executable throws exactly the expected exception type
|
||||
*/
|
||||
static <T extends Throwable> T assertThrowsExactly(Class<T> expectedType, Executable executable);
|
||||
static <T extends Throwable> T assertThrowsExactly(Class<T> expectedType, Executable executable, String message);
|
||||
static <T extends Throwable> T assertThrowsExactly(Class<T> expectedType, Executable executable, Supplier<String> 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<String> messageSupplier);
|
||||
static <T> T assertDoesNotThrow(ThrowingSupplier<T> supplier);
|
||||
static <T> T assertDoesNotThrow(ThrowingSupplier<T> supplier, String message);
|
||||
static <T> T assertDoesNotThrow(ThrowingSupplier<T> supplier, Supplier<String> 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<String> messageSupplier);
|
||||
static <T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier);
|
||||
static <T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier, String message);
|
||||
static <T> T assertTimeout(Duration timeout, ThrowingSupplier<T> supplier, Supplier<String> 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<String> messageSupplier);
|
||||
static <T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier);
|
||||
static <T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier, String message);
|
||||
static <T> T assertTimeoutPreemptively(Duration timeout, ThrowingSupplier<T> supplier, Supplier<String> 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<String> messageSupplier);
|
||||
static <T> T assertInstanceOf(Class<T> expectedType, Object actualValue);
|
||||
static <T> T assertInstanceOf(Class<T> expectedType, Object actualValue, String message);
|
||||
static <T> T assertInstanceOf(Class<T> expectedType, Object actualValue, Supplier<String> 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<Executable> executables);
|
||||
static void assertAll(String heading, Collection<Executable> executables);
|
||||
static void assertAll(Stream<Executable> executables);
|
||||
static void assertAll(String heading, Stream<Executable> 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<Executable> 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<String> messageSupplier);
|
||||
static <T> T fail();
|
||||
static <T> T fail(String message);
|
||||
static <T> T fail(String message, Throwable cause);
|
||||
static <T> T fail(Throwable cause);
|
||||
static <T> T fail(Supplier<String> 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<String> messageSupplier);
|
||||
static void assumeTrue(BooleanSupplier assumptionSupplier);
|
||||
static void assumeTrue(BooleanSupplier assumptionSupplier, String message);
|
||||
static void assumeTrue(BooleanSupplier assumptionSupplier, Supplier<String> 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<String> messageSupplier);
|
||||
static void assumeFalse(BooleanSupplier assumptionSupplier);
|
||||
static void assumeFalse(BooleanSupplier assumptionSupplier, String message);
|
||||
static void assumeFalse(BooleanSupplier assumptionSupplier, Supplier<String> 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();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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<? extends DisplayNameGenerator> 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<String> getTags();
|
||||
Optional<Class<?>> getTestClass();
|
||||
Optional<Method> 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<? extends MethodOrderer> value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure test class execution order
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TestClassOrder {
|
||||
Class<? extends ClassOrderer> 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
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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 <T> Stream<DynamicTest> stream(Iterator<T> inputGenerator,
|
||||
Function<? super T, String> displayNameGenerator,
|
||||
ThrowingConsumer<? super T> testExecutor);
|
||||
|
||||
/**
|
||||
* Create a stream of dynamic tests from input stream
|
||||
*/
|
||||
static <T> Stream<DynamicTest> stream(Stream<T> inputStream,
|
||||
Function<? super T, String> displayNameGenerator,
|
||||
ThrowingConsumer<? super T> testExecutor);
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
```java
|
||||
class DynamicTestExample {
|
||||
|
||||
@TestFactory
|
||||
Stream<DynamicTest> simpleTests() {
|
||||
return Stream.of("apple", "banana", "cherry")
|
||||
.map(fruit -> DynamicTest.dynamicTest(
|
||||
"test " + fruit,
|
||||
() -> {
|
||||
assertNotNull(fruit);
|
||||
assertTrue(fruit.length() > 3);
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
Collection<DynamicTest> 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<DynamicTest> dataStreamTests() {
|
||||
List<String> 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<DynamicNode> children);
|
||||
|
||||
/**
|
||||
* Create a dynamic container with display name, URI, and children
|
||||
*/
|
||||
static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Stream<DynamicNode> children);
|
||||
|
||||
/**
|
||||
* Create a dynamic container with display name and iterable children
|
||||
*/
|
||||
static DynamicContainer dynamicContainer(String displayName, Iterable<DynamicNode> children);
|
||||
|
||||
/**
|
||||
* Create a dynamic container with display name, URI, and iterable children
|
||||
*/
|
||||
static DynamicContainer dynamicContainer(String displayName, URI testSourceUri, Iterable<DynamicNode> children);
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
```java
|
||||
class DynamicContainerExample {
|
||||
|
||||
@TestFactory
|
||||
Stream<DynamicNode> 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<DynamicNode> 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<URI> 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 <T> Named<T> 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<DynamicTest> namedTests() {
|
||||
List<Named<String>> 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<DynamicTest> namedExecutableTests() {
|
||||
List<NamedExecutable> 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<DynamicTest> 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<DynamicNode> testUsersByRole() {
|
||||
UserRepository repository = new UserRepository();
|
||||
Map<String, List<User>> 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<DynamicTest> 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<DynamicNode> testConfigurationGroups() throws IOException {
|
||||
Map<String, Properties> 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<String, Properties> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -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<? extends Extension>[] 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<Object> getTarget();
|
||||
boolean isAnnotated(Class<? extends Annotation> annotationType);
|
||||
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
|
||||
<A extends Annotation> List<A> findRepeatableAnnotations(Class<A> annotationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-based parameter resolver base class
|
||||
*/
|
||||
abstract class TypeBasedParameterResolver<T> implements ParameterResolver {
|
||||
private final Class<T> parameterType;
|
||||
|
||||
protected TypeBasedParameterResolver(Class<T> 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<Path> {
|
||||
|
||||
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<String> getReason();
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```java
|
||||
class SystemPropertyCondition implements ExecutionCondition {
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
Optional<SystemProperty> 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<Object> 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<String> getReason();
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch test execution and results
|
||||
*/
|
||||
interface TestWatcher extends Extension {
|
||||
/**
|
||||
* Called when test is disabled
|
||||
*/
|
||||
default void testDisabled(ExtensionContext context, Optional<String> 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<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
invocation.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept test class constructor invocation
|
||||
*/
|
||||
default <T> T interceptTestClassConstructor(Invocation<T> invocation,
|
||||
ReflectiveInvocationContext<Constructor<T>> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
return invocation.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept BeforeAll method invocation
|
||||
*/
|
||||
default void interceptBeforeAllMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
invocation.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept BeforeEach method invocation
|
||||
*/
|
||||
default void interceptBeforeEachMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
invocation.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept AfterEach method invocation
|
||||
*/
|
||||
default void interceptAfterEachMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> invocationContext,
|
||||
ExtensionContext extensionContext) throws Throwable {
|
||||
invocation.proceed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept AfterAll method invocation
|
||||
*/
|
||||
default void interceptAfterAllMethod(Invocation<Void> invocation,
|
||||
ReflectiveInvocationContext<Method> 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<Retry> 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<ExtensionContext> getParent();
|
||||
|
||||
/**
|
||||
* Get root context
|
||||
*/
|
||||
ExtensionContext getRoot();
|
||||
|
||||
/**
|
||||
* Get unique ID
|
||||
*/
|
||||
String getUniqueId();
|
||||
|
||||
/**
|
||||
* Get display name
|
||||
*/
|
||||
String getDisplayName();
|
||||
|
||||
/**
|
||||
* Get all tags
|
||||
*/
|
||||
Set<String> getTags();
|
||||
|
||||
/**
|
||||
* Get annotated element (class or method)
|
||||
*/
|
||||
Optional<AnnotatedElement> getElement();
|
||||
|
||||
/**
|
||||
* Get test class
|
||||
*/
|
||||
Optional<Class<?>> getTestClass();
|
||||
|
||||
/**
|
||||
* Get required test class (throws if not present)
|
||||
*/
|
||||
Class<?> getRequiredTestClass();
|
||||
|
||||
/**
|
||||
* Get test instance lifecycle
|
||||
*/
|
||||
Optional<TestInstance.Lifecycle> getTestInstanceLifecycle();
|
||||
|
||||
/**
|
||||
* Get test instance (may be null for static methods)
|
||||
*/
|
||||
Optional<Object> getTestInstance();
|
||||
|
||||
/**
|
||||
* Get all test instances for nested tests
|
||||
*/
|
||||
Optional<TestInstances> getTestInstances();
|
||||
|
||||
/**
|
||||
* Get test method
|
||||
*/
|
||||
Optional<Method> getTestMethod();
|
||||
|
||||
/**
|
||||
* Get required test method (throws if not present)
|
||||
*/
|
||||
Method getRequiredTestMethod();
|
||||
|
||||
/**
|
||||
* Get execution exception if test failed
|
||||
*/
|
||||
Optional<Throwable> getExecutionException();
|
||||
|
||||
/**
|
||||
* Get configuration parameter
|
||||
*/
|
||||
Optional<String> getConfigurationParameter(String key);
|
||||
|
||||
/**
|
||||
* Get store for sharing data
|
||||
*/
|
||||
Store getStore(Namespace namespace);
|
||||
|
||||
/**
|
||||
* Publish entry to test report
|
||||
*/
|
||||
void publishReportEntry(Map<String, String> 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> V get(Object key, Class<V> requiredType);
|
||||
<K, V> Object getOrComputeIfAbsent(K key, Function<K, V> defaultCreator);
|
||||
<K, V> V getOrComputeIfAbsent(K key, Function<K, V> defaultCreator, Class<V> requiredType);
|
||||
void put(Object key, Object value);
|
||||
Object remove(Object key);
|
||||
<V> V remove(Object key, Class<V> requiredType);
|
||||
<K, V> V getOrDefault(K key, Class<V> 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<String> 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<T> {
|
||||
/**
|
||||
* Proceed with the invocation
|
||||
*/
|
||||
T proceed() throws Throwable;
|
||||
|
||||
/**
|
||||
* Skip the invocation
|
||||
*/
|
||||
void skip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Context for reflective invocations
|
||||
*/
|
||||
interface ReflectiveInvocationContext<T> {
|
||||
/**
|
||||
* Get the executable being invoked (Constructor or Method)
|
||||
*/
|
||||
T getExecutable();
|
||||
|
||||
/**
|
||||
* Get the arguments for the invocation
|
||||
*/
|
||||
List<Object> getArguments();
|
||||
|
||||
/**
|
||||
* Get the target instance (null for static methods/constructors)
|
||||
*/
|
||||
Optional<Object> 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<Object> getEnclosingInstances();
|
||||
|
||||
/**
|
||||
* Get all test instances (enclosing + innermost)
|
||||
*/
|
||||
List<Object> getAllInstances();
|
||||
|
||||
/**
|
||||
* Find test instance of specific type
|
||||
*/
|
||||
<T> Optional<T> findInstance(Class<T> requiredType);
|
||||
}
|
||||
```
|
||||
|
|
@ -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
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.12.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
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<T> 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<DynamicTest> dynamicTests();
|
||||
|
||||
static DynamicTest dynamicTest(String displayName, Executable executable);
|
||||
static DynamicContainer dynamicContainer(String displayName, Stream<DynamicNode> 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<String> getTags();
|
||||
Optional<Class<?>> getTestClass();
|
||||
Optional<Method> getTestMethod();
|
||||
}
|
||||
|
||||
interface TestReporter {
|
||||
void publishEntry(Map<String, String> 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> {
|
||||
T get() throws Throwable;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface ThrowingConsumer<T> {
|
||||
void accept(T t) throws Throwable;
|
||||
}
|
||||
```
|
||||
|
|
@ -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<Lock> provideForClass(ExtensionContext context);
|
||||
Set<Lock> provideForNestedClass(ExtensionContext context);
|
||||
Set<Lock> 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<? extends TempDirFactory> 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
|
||||
```
|
||||
|
|
@ -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<? extends Enum<?>> 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<String> stringProvider() {
|
||||
return Stream.of("apple", "banana", "cherry");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("personProvider")
|
||||
void testPersons(Person person) {
|
||||
assertNotNull(person.getName());
|
||||
assertTrue(person.getAge() > 0);
|
||||
}
|
||||
|
||||
static Stream<Person> 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<Arguments> 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<String> fruits = Arrays.asList("apple", "banana", "cherry");
|
||||
|
||||
@ParameterizedTest
|
||||
@FieldSource("fruits")
|
||||
void testWithFieldSource(String fruit) {
|
||||
assertNotNull(fruit);
|
||||
assertTrue(fruit.length() > 3);
|
||||
}
|
||||
|
||||
static Stream<Arguments> 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<? extends ArgumentsProvider> 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<? extends Arguments> provideArguments(ExtensionContext context) throws Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for annotation-based providers
|
||||
*/
|
||||
abstract class AnnotationBasedArgumentsProvider<T extends Annotation> 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<RandomIntegers> {
|
||||
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<Arguments> 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<? extends ArgumentConverter> 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<S, T> {
|
||||
/**
|
||||
* Convert source argument to target type
|
||||
*/
|
||||
T convert(S source, ParameterContext context) throws ArgumentConversionException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple converter for single argument types
|
||||
*/
|
||||
abstract class SimpleArgumentConverter<S, T> implements ArgumentConverter<S, T> {
|
||||
@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<S, T> extends SimpleArgumentConverter<S, T> {
|
||||
private final Class<S> sourceType;
|
||||
private final Class<T> targetType;
|
||||
|
||||
protected TypedArgumentConverter(Class<S> sourceType, Class<T> 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<String, Person> {
|
||||
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<? extends ArgumentsAggregator> 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> T get(int index, Class<T> 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<Object> 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<Arguments> 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);
|
||||
}
|
||||
```
|
||||
|
|
@ -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."
|
||||
}
|
||||
486
.tessl/tiles/tessl/npm-babel--core/docs/configuration.md
Normal file
486
.tessl/tiles/tessl/npm-babel--core/docs/configuration.md
Normal file
|
|
@ -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<ResolvedConfig | null>;
|
||||
|
||||
/**
|
||||
* 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<ConfigItem>;
|
||||
/** Resolved presets with their options */
|
||||
presets: Array<ConfigItem>;
|
||||
/** 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<PartialConfig | null>;
|
||||
|
||||
/**
|
||||
* 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<PluginAPI> | 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<ConfigItem<PluginAPI> | 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<PluginAPI> | 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<T = PluginAPI> {
|
||||
/** 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);
|
||||
}
|
||||
```
|
||||
398
.tessl/tiles/tessl/npm-babel--core/docs/index.md
Normal file
398
.tessl/tiles/tessl/npm-babel--core/docs/index.md
Normal file
|
|
@ -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<FileResult | null>;
|
||||
|
||||
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<ParseResult | null>;
|
||||
|
||||
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<ResolvedConfig | null>;
|
||||
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<PartialConfig | null>;
|
||||
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<PluginAPI> | null;
|
||||
function createConfigItemAsync(
|
||||
target: PluginTarget,
|
||||
options?: any
|
||||
): Promise<ConfigItem<PluginAPI> | null>;
|
||||
function createConfigItem(
|
||||
target: PluginTarget,
|
||||
options: any,
|
||||
callback: (err: Error | null, item: ConfigItem<PluginAPI> | 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<T = PluginAPI> {
|
||||
/** 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<S = unknown> = {
|
||||
/** 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<T = any> {
|
||||
/** 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[];
|
||||
}
|
||||
```
|
||||
430
.tessl/tiles/tessl/npm-babel--core/docs/parsing.md
Normal file
430
.tessl/tiles/tessl/npm-babel--core/docs/parsing.md
Normal file
|
|
@ -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<ParseResult | null>;
|
||||
|
||||
/**
|
||||
* 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 <div>Hello World</div>;
|
||||
};
|
||||
`, {
|
||||
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);
|
||||
```
|
||||
327
.tessl/tiles/tessl/npm-babel--core/docs/transformation.md
Normal file
327
.tessl/tiles/tessl/npm-babel--core/docs/transformation.md
Normal file
|
|
@ -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<FileResult | null>;
|
||||
|
||||
/**
|
||||
* 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 = () => <div>Hello</div>;
|
||||
`, {
|
||||
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<FileResult | null>;
|
||||
|
||||
/**
|
||||
* 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<FileResult | null>;
|
||||
|
||||
/**
|
||||
* 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<string | [string, any] | PluginFunction | [PluginFunction, any]>;
|
||||
/** Presets to apply during transformation (applied before plugins) */
|
||||
presets?: Array<string | [string, any] | PresetFunction | [PresetFunction, any]>;
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
564
.tessl/tiles/tessl/npm-babel--core/docs/utilities.md
Normal file
564
.tessl/tiles/tessl/npm-babel--core/docs/utilities.md
Normal file
|
|
@ -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<S = unknown> = import("@babel/traverse").Visitor<S>;
|
||||
```
|
||||
|
||||
**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<import("@babel/types").Program>;
|
||||
/** 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<T extends import("@babel/types").Node>(
|
||||
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
|
||||
7
.tessl/tiles/tessl/npm-babel--core/tile.json
Normal file
7
.tessl/tiles/tessl/npm-babel--core/tile.json
Normal file
|
|
@ -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."
|
||||
}
|
||||
376
.tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md
Normal file
376
.tessl/tiles/tessl/npm-babel--preset-typescript/docs/index.md
Normal file
|
|
@ -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<PresetObject>;
|
||||
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<string | [string, any]>;
|
||||
overrides: Array<{
|
||||
test?: RegExp | ((filename?: string) => boolean);
|
||||
sourceType?: "module" | "unambiguous";
|
||||
plugins: Array<string | [string, any]>;
|
||||
}>;
|
||||
}
|
||||
```
|
||||
|
||||
### 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<Options>;
|
||||
```
|
||||
|
||||
**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';
|
||||
```
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
```
|
||||
362
.tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md
Normal file
362
.tessl/tiles/tessl/npm-better-sqlite3/docs/database-utilities.md
Normal file
|
|
@ -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<BackupProgress>} 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());
|
||||
```
|
||||
280
.tessl/tiles/tessl/npm-better-sqlite3/docs/index.md
Normal file
280
.tessl/tiles/tessl/npm-better-sqlite3/docs/index.md
Normal file
|
|
@ -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
|
||||
}
|
||||
```
|
||||
|
|
@ -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<Object>} 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"
|
||||
```
|
||||
|
|
@ -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
|
||||
});
|
||||
```
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
7
.tessl/tiles/tessl/npm-better-sqlite3/tile.json
Normal file
7
.tessl/tiles/tessl/npm-better-sqlite3/tile.json
Normal file
|
|
@ -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"
|
||||
}
|
||||
407
.tessl/tiles/tessl/npm-jest/docs/cli-usage.md
Normal file
407
.tessl/tiles/tessl/npm-jest/docs/cli-usage.md
Normal file
|
|
@ -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<string>): Promise<Config.Argv>
|
||||
```
|
||||
|
||||
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.
|
||||
513
.tessl/tiles/tessl/npm-jest/docs/configuration.md
Normal file
513
.tessl/tiles/tessl/npm-jest/docs/configuration.md
Normal file
|
|
@ -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<string>;
|
||||
testRegex?: string | Array<string>;
|
||||
testPathIgnorePatterns?: Array<string>;
|
||||
|
||||
// Test environment
|
||||
testEnvironment?: string;
|
||||
testEnvironmentOptions?: Record<string, any>;
|
||||
|
||||
// Module resolution
|
||||
moduleDirectories?: Array<string>;
|
||||
moduleFileExtensions?: Array<string>;
|
||||
moduleNameMapper?: Record<string, string>;
|
||||
modulePaths?: Array<string>;
|
||||
|
||||
// Transforms
|
||||
transform?: Record<string, string>;
|
||||
transformIgnorePatterns?: Array<string>;
|
||||
|
||||
// Setup
|
||||
setupFiles?: Array<string>;
|
||||
setupFilesAfterEnv?: Array<string>;
|
||||
|
||||
// Coverage
|
||||
collectCoverage?: boolean;
|
||||
collectCoverageFrom?: Array<string>;
|
||||
coverageDirectory?: string;
|
||||
coveragePathIgnorePatterns?: Array<string>;
|
||||
coverageProvider?: "babel" | "v8";
|
||||
coverageReporters?: Array<string>;
|
||||
coverageThreshold?: Record<string, Record<string, number>>;
|
||||
|
||||
// Execution
|
||||
maxWorkers?: number | string;
|
||||
testTimeout?: number;
|
||||
|
||||
// Output
|
||||
verbose?: boolean;
|
||||
silent?: boolean;
|
||||
|
||||
// Project structure
|
||||
rootDir?: string;
|
||||
roots?: Array<string>;
|
||||
projects?: Array<string | Config>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global configuration that applies to the entire Jest run
|
||||
*/
|
||||
interface Config.GlobalConfig {
|
||||
bail: number;
|
||||
changedFilesWithAncestor: boolean;
|
||||
changedSince?: string;
|
||||
ci: boolean;
|
||||
collectCoverage: boolean;
|
||||
collectCoverageFrom: Array<string>;
|
||||
collectCoverageOnlyFrom?: Record<string, boolean>;
|
||||
coverageDirectory: string;
|
||||
coveragePathIgnorePatterns?: Array<string>;
|
||||
coverageProvider: "babel" | "v8";
|
||||
coverageReporters: Array<string>;
|
||||
coverageThreshold?: Record<string, Record<string, number>>;
|
||||
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<string>;
|
||||
randomize?: boolean;
|
||||
rootDir: string;
|
||||
runTestsByPath: boolean;
|
||||
seed?: number;
|
||||
silent: boolean;
|
||||
skipFilter: boolean;
|
||||
testFailureExitCode: number;
|
||||
testNamePattern?: string;
|
||||
testPathPattern: string;
|
||||
testPathPatterns: Array<string>;
|
||||
testResultsProcessor?: string;
|
||||
testSequencer: string;
|
||||
testTimeout?: number;
|
||||
updateSnapshot: SnapshotUpdateState;
|
||||
useStderr: boolean;
|
||||
verbose?: boolean;
|
||||
watch: boolean;
|
||||
watchAll: boolean;
|
||||
watchPathIgnorePatterns: Array<string>;
|
||||
watchman: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-project configuration
|
||||
*/
|
||||
interface Config.ProjectConfig {
|
||||
automock: boolean;
|
||||
cache: boolean;
|
||||
cacheDirectory: string;
|
||||
clearMocks: boolean;
|
||||
collectCoverageFrom: Array<string>;
|
||||
coveragePathIgnorePatterns: Array<string>;
|
||||
cwd: string;
|
||||
dependencyExtractor?: string;
|
||||
detectLeaks: boolean;
|
||||
displayName?: string;
|
||||
errorOnDeprecated: boolean;
|
||||
extensionsToTreatAsEsm: Array<string>;
|
||||
extraGlobals: Array<string>;
|
||||
forceCoverageMatch: Array<string>;
|
||||
globalSetup?: string;
|
||||
globalTeardown?: string;
|
||||
globals: Record<string, unknown>;
|
||||
haste: HasteConfig;
|
||||
injectGlobals: boolean;
|
||||
moduleDirectories: Array<string>;
|
||||
moduleFileExtensions: Array<string>;
|
||||
moduleNameMapper: Array<[string, string]>;
|
||||
modulePaths?: Array<string>;
|
||||
modulePathIgnorePatterns: Array<string>;
|
||||
preset?: string;
|
||||
prettierPath: string;
|
||||
resetMocks: boolean;
|
||||
resetModules: boolean;
|
||||
resolver?: string;
|
||||
restoreMocks: boolean;
|
||||
rootDir: string;
|
||||
roots: Array<string>;
|
||||
runner: string;
|
||||
setupFiles: Array<string>;
|
||||
setupFilesAfterEnv: Array<string>;
|
||||
skipFilter: boolean;
|
||||
skipNodeResolution?: boolean;
|
||||
slowTestThreshold: number;
|
||||
snapshotResolver?: string;
|
||||
snapshotSerializers: Array<string>;
|
||||
testEnvironment: string;
|
||||
testEnvironmentOptions: Record<string, unknown>;
|
||||
testLocationInResults: boolean;
|
||||
testMatch: Array<string>;
|
||||
testPathIgnorePatterns: Array<string>;
|
||||
testRegex: Array<string | RegExp>;
|
||||
testRunner: string;
|
||||
testURL?: string;
|
||||
timers: "real" | "fake";
|
||||
transform: Array<[string, string, Record<string, unknown>]>;
|
||||
transformIgnorePatterns: Array<string>;
|
||||
unmockedModulePathPatterns?: Array<string>;
|
||||
watchPathIgnorePatterns: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<string>;
|
||||
testTimeout?: number;
|
||||
|
||||
// Watch mode
|
||||
watch?: boolean;
|
||||
watchAll?: boolean;
|
||||
watchPathIgnorePatterns?: Array<string>;
|
||||
|
||||
// Coverage
|
||||
collectCoverage?: boolean;
|
||||
coverage?: boolean;
|
||||
collectCoverageFrom?: Array<string>;
|
||||
coverageDirectory?: string;
|
||||
coveragePathIgnorePatterns?: Array<string>;
|
||||
coverageProvider?: "babel" | "v8";
|
||||
coverageReporters?: Array<string>;
|
||||
coverageThreshold?: Record<string, number>;
|
||||
|
||||
// Output
|
||||
json?: boolean;
|
||||
outputFile?: string;
|
||||
verbose?: boolean;
|
||||
silent?: boolean;
|
||||
noStackTrace?: boolean;
|
||||
color?: boolean;
|
||||
colors?: boolean;
|
||||
|
||||
// Configuration
|
||||
config?: string;
|
||||
rootDir?: string;
|
||||
roots?: Array<string>;
|
||||
projects?: Array<string>;
|
||||
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: {
|
||||
"^@/(.*)$": "<rootDir>/src/$1",
|
||||
"\\.(css|less|scss)$": "identity-obj-proxy"
|
||||
},
|
||||
|
||||
// Transforms
|
||||
transform: {
|
||||
"^.+\\.jsx?$": "babel-jest",
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
|
||||
// Setup
|
||||
setupFilesAfterEnv: ["<rootDir>/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: {
|
||||
"^@/(.*)$": "<rootDir>/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: ["<rootDir>/packages/client/**/*.test.js"],
|
||||
testEnvironment: "jsdom",
|
||||
setupFilesAfterEnv: ["<rootDir>/packages/client/src/setupTests.js"]
|
||||
},
|
||||
{
|
||||
displayName: "server",
|
||||
testMatch: ["<rootDir>/packages/server/**/*.test.js"],
|
||||
testEnvironment: "node",
|
||||
setupFilesAfterEnv: ["<rootDir>/packages/server/src/setupTests.js"]
|
||||
},
|
||||
{
|
||||
displayName: "shared",
|
||||
testMatch: ["<rootDir>/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.
|
||||
212
.tessl/tiles/tessl/npm-jest/docs/index.md
Normal file
212
.tessl/tiles/tessl/npm-jest/docs/index.md
Normal file
|
|
@ -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: ["<rootDir>/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<string>
|
||||
): Promise<{
|
||||
results: AggregatedResult;
|
||||
globalConfig: Config.GlobalConfig;
|
||||
}>;
|
||||
|
||||
function run(maybeArgv?: Array<string>, project?: string): Promise<void>;
|
||||
```
|
||||
|
||||
[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<string>): Promise<Config.Argv>;
|
||||
```
|
||||
|
||||
[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<string>): SearchResult;
|
||||
findRelatedTests(allPaths: Set<string>, collectCoverage: boolean): Promise<SearchResult>;
|
||||
}
|
||||
```
|
||||
|
||||
[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<string>;
|
||||
transform?: Record<string, string>;
|
||||
setupFilesAfterEnv?: Array<string>;
|
||||
moduleNameMapping?: Record<string, string>;
|
||||
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<TestScheduler>;
|
||||
|
||||
class TestScheduler {
|
||||
constructor(globalConfig: Config.GlobalConfig, context: TestSchedulerContext);
|
||||
addReporter(reporter: Reporter): void;
|
||||
scheduleTests(tests: Array<Test>, watcher: TestWatcher): Promise<AggregatedResult>;
|
||||
}
|
||||
```
|
||||
|
||||
[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<Error>;
|
||||
snapshot: SnapshotSummary;
|
||||
success: boolean;
|
||||
startTime: number;
|
||||
testResults: Array<TestResult>;
|
||||
wasInterrupted: boolean;
|
||||
}
|
||||
|
||||
interface SearchResult {
|
||||
noSCM?: boolean;
|
||||
stats?: Stats;
|
||||
collectCoverageFrom?: Set<string>;
|
||||
tests: Array<Test>;
|
||||
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;
|
||||
}
|
||||
```
|
||||
307
.tessl/tiles/tessl/npm-jest/docs/test-discovery.md
Normal file
307
.tessl/tiles/tessl/npm-jest/docs/test-discovery.md
Normal file
|
|
@ -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<string>): 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<string>, collectCoverage: boolean): Promise<SearchResult>;
|
||||
|
||||
/**
|
||||
* 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<SearchResult>;
|
||||
}
|
||||
|
||||
interface SearchResult {
|
||||
noSCM?: boolean;
|
||||
stats?: Stats;
|
||||
collectCoverageFrom?: Set<string>;
|
||||
tests: Array<Test>;
|
||||
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.
|
||||
280
.tessl/tiles/tessl/npm-jest/docs/test-runner.md
Normal file
280
.tessl/tiles/tessl/npm-jest/docs/test-runner.md
Normal file
|
|
@ -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<string>
|
||||
): 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<Error>;
|
||||
snapshot: SnapshotSummary;
|
||||
success: boolean;
|
||||
startTime: number;
|
||||
testResults: Array<TestResult>;
|
||||
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<string>, project?: string): Promise<void>;
|
||||
```
|
||||
|
||||
**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<string>): Promise<Config.Argv>;
|
||||
|
||||
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<string>;
|
||||
testTimeout?: number;
|
||||
|
||||
// Watch mode options
|
||||
watch?: boolean;
|
||||
watchAll?: boolean;
|
||||
watchPathIgnorePatterns?: Array<string>;
|
||||
|
||||
// Coverage options
|
||||
collectCoverage?: boolean;
|
||||
coverage?: boolean;
|
||||
collectCoverageFrom?: Array<string>;
|
||||
coverageDirectory?: string;
|
||||
coveragePathIgnorePatterns?: Array<string>;
|
||||
coverageProvider?: "babel" | "v8";
|
||||
coverageReporters?: Array<string>;
|
||||
coverageThreshold?: Record<string, number>;
|
||||
|
||||
// Output options
|
||||
json?: boolean;
|
||||
outputFile?: string;
|
||||
verbose?: boolean;
|
||||
silent?: boolean;
|
||||
noStackTrace?: boolean;
|
||||
color?: boolean;
|
||||
colors?: boolean;
|
||||
|
||||
// Configuration options
|
||||
config?: string;
|
||||
rootDir?: string;
|
||||
roots?: Array<string>;
|
||||
projects?: Array<string>;
|
||||
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;
|
||||
}
|
||||
```
|
||||
501
.tessl/tiles/tessl/npm-jest/docs/test-scheduling.md
Normal file
501
.tessl/tiles/tessl/npm-jest/docs/test-scheduling.md
Normal file
|
|
@ -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<Test>, watcher: TestWatcher): Promise<AggregatedResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<TestScheduler>;
|
||||
|
||||
type TestSchedulerContext = ReporterContext & TestRunnerContext;
|
||||
|
||||
type ReporterConstructor = new (
|
||||
globalConfig: Config.GlobalConfig,
|
||||
reporterConfig: Record<string, unknown>,
|
||||
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<Test>) {
|
||||
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<string, unknown>,
|
||||
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<TestContext>, 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<string>) {
|
||||
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<Test>): 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<Test>) {
|
||||
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<string, SchedulingStrategy> = {
|
||||
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<Test>,
|
||||
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<Test>) {
|
||||
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.
|
||||
7
.tessl/tiles/tessl/npm-jest/tile.json
Normal file
7
.tessl/tiles/tessl/npm-jest/tile.json
Normal file
|
|
@ -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."
|
||||
}
|
||||
435
.tessl/tiles/tessl/npm-mocha/docs/browser.md
Normal file
435
.tessl/tiles/tessl/npm-mocha/docs/browser.md
Normal file
|
|
@ -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
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="node_modules/mocha/mocha.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
|
||||
<script src="node_modules/mocha/mocha.js"></script>
|
||||
<script>
|
||||
// Setup Mocha for browser
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
reporter: 'html',
|
||||
timeout: 5000,
|
||||
slow: 100
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Load test files -->
|
||||
<script src="test/browser-tests.js"></script>
|
||||
|
||||
<script>
|
||||
// Run tests when page loads
|
||||
mocha.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```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 <div id="mocha"></div> 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)
|
||||
*/
|
||||
// <script src="node_modules/mocha/mocha.js"></script>
|
||||
// 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 = '<div id="app"></div>';
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('should create DOM elements', async function() {
|
||||
const app = document.getElementById('app');
|
||||
app.innerHTML = '<button>Click me</button>';
|
||||
|
||||
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`);
|
||||
});
|
||||
```
|
||||
457
.tessl/tiles/tessl/npm-mocha/docs/cli-config.md
Normal file
457
.tessl/tiles/tessl/npm-mocha/docs/cli-config.md
Normal file
|
|
@ -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 <pattern> # Filter tests by pattern (string or regex)
|
||||
--fgrep <string> # Filter tests by fixed string
|
||||
--invert # Invert grep pattern
|
||||
--recursive # Look for tests in subdirectories
|
||||
|
||||
# Test Execution
|
||||
--timeout <ms> # Set global timeout (default: 2000ms)
|
||||
--slow <ms> # Set slow test threshold (default: 75ms)
|
||||
--retries <count> # Set retry count for failed tests
|
||||
--bail # Bail on first test failure
|
||||
--parallel # Run tests in parallel
|
||||
--jobs <count> # Number of parallel jobs (default: CPU count - 1)
|
||||
|
||||
# Interfaces and Reporters
|
||||
--ui <name> # Set interface: bdd, tdd, qunit, exports
|
||||
--reporter <name> # Set reporter (default: spec)
|
||||
--reporter-option <key=value> # 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 <names> # 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 <globs> # Specify files to watch (comma-separated)
|
||||
--watch-ignore <globs> # Specify files to ignore when watching
|
||||
--file <file> # Include file before other test files
|
||||
--require <module> # Require module before running tests
|
||||
--loader <loader> # Use custom loader for test files
|
||||
|
||||
# Configuration Files
|
||||
--config <path> # Specify config file path
|
||||
--package <path> # Specify package.json path
|
||||
--opts <path> # Specify mocha.opts file (deprecated)
|
||||
|
||||
# Node.js Specific
|
||||
--inspect # Enable Node.js inspector
|
||||
--inspect-brk # Enable inspector and break before start
|
||||
--node-option <option> # Pass option to Node.js
|
||||
|
||||
# Miscellaneous
|
||||
--version # Show version
|
||||
--help # Show help
|
||||
--reporter-options <options> # (deprecated, use --reporter-option)
|
||||
```
|
||||
|
||||
### Configuration Files
|
||||
|
||||
Mocha supports multiple configuration file formats.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Configuration file formats and locations
|
||||
*/
|
||||
|
||||
// .mocharc.json - JSON configuration
|
||||
{
|
||||
"ui": "bdd",
|
||||
"reporter": "spec",
|
||||
"timeout": 5000,
|
||||
"slow": 100,
|
||||
"recursive": true,
|
||||
"require": ["test/setup.js"],
|
||||
"grep": "User"
|
||||
}
|
||||
|
||||
// .mocharc.yml - YAML configuration
|
||||
ui: bdd
|
||||
reporter: spec
|
||||
timeout: 5000
|
||||
slow: 100
|
||||
recursive: true
|
||||
require:
|
||||
- test/setup.js
|
||||
grep: User
|
||||
|
||||
// .mocharc.js - JavaScript configuration
|
||||
module.exports = {
|
||||
ui: 'bdd',
|
||||
reporter: 'spec',
|
||||
timeout: 5000,
|
||||
slow: 100,
|
||||
recursive: true,
|
||||
require: ['test/setup.js'],
|
||||
grep: 'User'
|
||||
};
|
||||
|
||||
// package.json - mocha field
|
||||
{
|
||||
"mocha": {
|
||||
"ui": "bdd",
|
||||
"reporter": "spec",
|
||||
"timeout": 5000,
|
||||
"recursive": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options Interface
|
||||
|
||||
Complete configuration options available programmatically and via config files.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Complete Mocha configuration options
|
||||
*/
|
||||
interface MochaOptions {
|
||||
// Test Selection
|
||||
grep?: string | RegExp; // Filter tests by pattern
|
||||
fgrep?: string; // Filter by fixed string
|
||||
invert?: boolean; // Invert grep pattern
|
||||
|
||||
// Test Execution
|
||||
timeout?: number; // Global timeout in ms
|
||||
slow?: number; // Slow test threshold in ms
|
||||
retries?: number; // Retry count for failed tests
|
||||
bail?: boolean; // Bail on first failure
|
||||
parallel?: boolean; // Enable parallel execution
|
||||
jobs?: number; // Number of parallel jobs
|
||||
|
||||
// Interfaces and Reporting
|
||||
ui?: string; // Test interface
|
||||
reporter?: string | Function; // Reporter name or constructor
|
||||
reporterOption?: object; // Reporter options
|
||||
reporterOptions?: object; // Reporter options (legacy)
|
||||
|
||||
// Test Behavior
|
||||
asyncOnly?: boolean; // Require async tests
|
||||
allowUncaught?: boolean; // Allow uncaught exceptions
|
||||
delay?: boolean; // Delay execution
|
||||
dryRun?: boolean; // Don't execute tests
|
||||
exit?: boolean; // Force exit after completion
|
||||
forbidOnly?: boolean; // Forbid .only tests
|
||||
forbidPending?: boolean; // Forbid .skip tests
|
||||
fullTrace?: boolean; // Show full stack traces
|
||||
|
||||
// Global Variables
|
||||
checkLeaks?: boolean; // Check for global leaks
|
||||
globals?: string[]; // Global variables to ignore
|
||||
|
||||
// Output and Formatting
|
||||
color?: boolean; // Enable colored output
|
||||
colors?: boolean; // Alias for color
|
||||
diff?: boolean; // Show diff on failure
|
||||
inlineDiffs?: boolean; // Show inline diffs
|
||||
sort?: boolean; // Sort test files
|
||||
|
||||
// File Operations
|
||||
watch?: boolean; // Watch for file changes
|
||||
watchFiles?: string[]; // Files to watch
|
||||
watchIgnore?: string[]; // Files to ignore
|
||||
file?: string[]; // Files to include first
|
||||
require?: string[]; // Modules to require
|
||||
loader?: string; // Custom loader
|
||||
recursive?: boolean; // Search subdirectories
|
||||
|
||||
// Configuration
|
||||
config?: string; // Config file path
|
||||
package?: string; // package.json path
|
||||
opts?: string; // mocha.opts file (deprecated)
|
||||
|
||||
// Root Hooks and Global Setup
|
||||
rootHooks?: MochaRootHookObject; // Root hooks
|
||||
globalSetup?: string | string[]; // Global setup functions
|
||||
globalTeardown?: string | string[]; // Global teardown functions
|
||||
enableGlobalSetup?: boolean; // Enable global setup
|
||||
enableGlobalTeardown?: boolean; // Enable global teardown
|
||||
|
||||
// Advanced Options
|
||||
isWorker?: boolean; // Running in worker process
|
||||
serializer?: string; // Custom serializer for parallel mode
|
||||
}
|
||||
|
||||
/**
|
||||
* Root hooks object for global setup/teardown
|
||||
*/
|
||||
interface MochaRootHookObject {
|
||||
beforeAll?: Function | Function[]; // Global before hooks
|
||||
beforeEach?: Function | Function[]; // Global beforeEach hooks
|
||||
afterAll?: Function | Function[]; // Global after hooks
|
||||
afterEach?: Function | Function[]; // Global afterEach hooks
|
||||
}
|
||||
```
|
||||
|
||||
### File Watching
|
||||
|
||||
Automatic test re-execution when files change.
|
||||
|
||||
```bash { .api }
|
||||
# Basic file watching
|
||||
mocha --watch
|
||||
|
||||
# Watch specific files
|
||||
mocha --watch --watch-files "src/**/*.js,test/**/*.js"
|
||||
|
||||
# Ignore files when watching
|
||||
mocha --watch --watch-ignore "node_modules/**,dist/**"
|
||||
|
||||
# Watch with grep pattern
|
||||
mocha --watch --grep "Unit"
|
||||
```
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Programmatic file watching
|
||||
*/
|
||||
const mocha = new Mocha({
|
||||
watch: true,
|
||||
watchFiles: ['src/**/*.js', 'test/**/*.js'],
|
||||
watchIgnore: ['node_modules/**', 'dist/**']
|
||||
});
|
||||
```
|
||||
|
||||
### Parallel Execution Configuration
|
||||
|
||||
Configure parallel test execution for improved performance.
|
||||
|
||||
```bash { .api }
|
||||
# Enable parallel execution
|
||||
mocha --parallel
|
||||
|
||||
# Set number of workers
|
||||
mocha --parallel --jobs 4
|
||||
|
||||
# Parallel with other options
|
||||
mocha --parallel --jobs 2 --timeout 10000 --reporter spec
|
||||
```
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Parallel execution options
|
||||
*/
|
||||
interface ParallelOptions {
|
||||
parallel: boolean; // Enable parallel execution
|
||||
jobs?: number; // Number of worker processes
|
||||
timeout?: number; // Worker timeout
|
||||
workerTimeout?: number; // Worker-specific timeout
|
||||
}
|
||||
|
||||
const mocha = new Mocha({
|
||||
parallel: true,
|
||||
jobs: 4,
|
||||
timeout: 10000
|
||||
});
|
||||
```
|
||||
|
||||
### Module Loading and Requirements
|
||||
|
||||
Load modules and setup files before tests.
|
||||
|
||||
```bash { .api }
|
||||
# Require modules before tests
|
||||
mocha --require test/setup.js --require should
|
||||
|
||||
# Multiple requires
|
||||
mocha --require babel-register --require test/helpers.js
|
||||
|
||||
# Include files before test files
|
||||
mocha --file test/globals.js --file test/setup.js
|
||||
```
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Module loading configuration
|
||||
*/
|
||||
interface ModuleLoadingOptions {
|
||||
require?: string[]; // Modules to require before tests
|
||||
file?: string[]; // Files to include before test files
|
||||
loader?: string; // Custom loader for test files
|
||||
}
|
||||
|
||||
// Example setup file (test/setup.js)
|
||||
const chai = require('chai');
|
||||
const sinon = require('sinon');
|
||||
|
||||
// Global setup
|
||||
global.expect = chai.expect;
|
||||
global.sinon = sinon;
|
||||
|
||||
// Configure chai
|
||||
chai.config.includeStack = true;
|
||||
chai.config.truncateThreshold = 0;
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Environment variables that affect Mocha behavior.
|
||||
|
||||
```bash { .api }
|
||||
# Common environment variables
|
||||
MOCHA_COLORS=1 # Enable colors
|
||||
MOCHA_GREP="pattern" # Set grep pattern
|
||||
MOCHA_TIMEOUT=5000 # Set timeout
|
||||
MOCHA_REPORTER=json # Set reporter
|
||||
NODE_ENV=test # Set Node environment
|
||||
DEBUG=mocha:* # Enable debug output
|
||||
|
||||
# Usage examples
|
||||
MOCHA_TIMEOUT=10000 mocha test/
|
||||
DEBUG=mocha:runner mocha --grep "slow tests"
|
||||
```
|
||||
|
||||
### Configuration Precedence
|
||||
|
||||
Order of configuration precedence (highest to lowest):
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Configuration precedence order
|
||||
* 1. Command line arguments (highest)
|
||||
* 2. Environment variables
|
||||
* 3. Configuration files (.mocharc.*)
|
||||
* 4. package.json "mocha" field
|
||||
* 5. Default values (lowest)
|
||||
*/
|
||||
|
||||
// Example: timeout value resolution
|
||||
// 1. --timeout 3000 (CLI)
|
||||
// 2. MOCHA_TIMEOUT=4000 (env)
|
||||
// 3. { "timeout": 5000 } (.mocharc.json)
|
||||
// 4. { "mocha": { "timeout": 6000 } } (package.json)
|
||||
// 5. 2000 (default)
|
||||
// Result: 3000ms (CLI wins)
|
||||
```
|
||||
|
||||
### Advanced CLI Usage
|
||||
|
||||
Complex CLI usage patterns and examples.
|
||||
|
||||
```bash { .api }
|
||||
# Complex test execution
|
||||
mocha test/unit/**/*.spec.js \
|
||||
--require test/setup.js \
|
||||
--require babel-register \
|
||||
--grep "User" \
|
||||
--reporter json \
|
||||
--timeout 5000 \
|
||||
--slow 100 \
|
||||
--bail \
|
||||
--check-leaks
|
||||
|
||||
# Parallel execution with custom options
|
||||
mocha --parallel \
|
||||
--jobs 4 \
|
||||
--timeout 10000 \
|
||||
--reporter spec \
|
||||
--require test/setup.js \
|
||||
"test/**/*.spec.js"
|
||||
|
||||
# Watch mode with filtering
|
||||
mocha --watch \
|
||||
--watch-files "src/**/*.js" \
|
||||
--watch-ignore "dist/**" \
|
||||
--grep "integration" \
|
||||
--reporter min
|
||||
|
||||
# Browser test preparation
|
||||
mocha --reporter json \
|
||||
--timeout 30000 \
|
||||
--slow 5000 \
|
||||
test/browser/**/*.js > browser-test-results.json
|
||||
|
||||
# Debug mode with inspector
|
||||
mocha --inspect-brk \
|
||||
--timeout 0 \
|
||||
--grep "specific test" \
|
||||
test/debug.spec.js
|
||||
```
|
||||
|
||||
### Legacy mocha.opts (Deprecated)
|
||||
|
||||
Legacy configuration file format (now deprecated in favor of .mocharc files).
|
||||
|
||||
```bash { .api }
|
||||
# test/mocha.opts (deprecated)
|
||||
--require test/setup.js
|
||||
--require should
|
||||
--reporter spec
|
||||
--ui bdd
|
||||
--timeout 5000
|
||||
--colors
|
||||
--recursive
|
||||
test/**/*.spec.js
|
||||
```
|
||||
|
||||
### Configuration Validation
|
||||
|
||||
Mocha validates configuration and provides helpful error messages.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Configuration validation examples
|
||||
*/
|
||||
|
||||
// Invalid reporter
|
||||
mocha --reporter nonexistent
|
||||
// Error: invalid reporter "nonexistent"
|
||||
|
||||
// Invalid timeout
|
||||
mocha --timeout abc
|
||||
// Error: timeout must be a number
|
||||
|
||||
// Conflicting options
|
||||
mocha --forbid-only test/with-only.js
|
||||
// Error: .only tests found but forbidden
|
||||
|
||||
// Invalid parallel configuration
|
||||
mocha --parallel --bail
|
||||
// Warning: --bail not supported in parallel mode
|
||||
```
|
||||
485
.tessl/tiles/tessl/npm-mocha/docs/execution.md
Normal file
485
.tessl/tiles/tessl/npm-mocha/docs/execution.md
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
# Test Execution and Runner
|
||||
|
||||
Core test execution functionality providing the Mocha class for configuration and the Runner class for test execution with comprehensive lifecycle management and parallel execution support.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Mocha Class
|
||||
|
||||
Main test framework class for configuration and execution.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Mocha constructor - creates a new test framework instance
|
||||
* @param options - Configuration options object
|
||||
*/
|
||||
class Mocha {
|
||||
constructor(options);
|
||||
|
||||
/**
|
||||
* Add a test file to be loaded
|
||||
* @param filepath - Path to test file
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
addFile(filepath);
|
||||
|
||||
/**
|
||||
* Set the reporter for output formatting
|
||||
* @param name - Reporter name or constructor function
|
||||
* @param options - Reporter-specific options
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
reporter(name, options);
|
||||
|
||||
/**
|
||||
* Set the test interface/UI
|
||||
* @param name - Interface name: 'bdd', 'tdd', 'qunit', 'exports'
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
ui(name);
|
||||
|
||||
/**
|
||||
* Set global timeout for all tests
|
||||
* @param ms - Timeout in milliseconds, 0 to disable
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
timeout(ms);
|
||||
|
||||
/**
|
||||
* Set threshold for slow test warnings
|
||||
* @param ms - Slow threshold in milliseconds
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
slow(ms);
|
||||
|
||||
/**
|
||||
* Set global retry count for failed tests
|
||||
* @param count - Number of retries
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
retries(count);
|
||||
|
||||
/**
|
||||
* Set grep pattern to filter tests
|
||||
* @param pattern - String or RegExp pattern
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
grep(pattern);
|
||||
|
||||
/**
|
||||
* Set fixed grep string (non-regex)
|
||||
* @param string - Fixed string to match
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
fgrep(string);
|
||||
|
||||
/**
|
||||
* Invert grep pattern matching
|
||||
* @param invert - Whether to invert pattern matching
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
invert(invert);
|
||||
|
||||
/**
|
||||
* Bail on first test failure
|
||||
* @param bail - Whether to bail on first failure
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
bail(bail);
|
||||
|
||||
/**
|
||||
* Enable/disable global leak detection
|
||||
* @param checkLeaks - Whether to check for global leaks
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
checkLeaks(checkLeaks);
|
||||
|
||||
/**
|
||||
* Set global variables to ignore during leak detection
|
||||
* @param globals - Array of global variable names
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
globals(globals);
|
||||
|
||||
/**
|
||||
* Run tests asynchronously only (no sync tests)
|
||||
* @param asyncOnly - Whether to require async tests
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
asyncOnly(asyncOnly);
|
||||
|
||||
/**
|
||||
* Allow uncaught exceptions to propagate
|
||||
* @param allowUncaught - Whether to allow uncaught exceptions
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
allowUncaught(allowUncaught);
|
||||
|
||||
/**
|
||||
* Add delay before running tests
|
||||
* @param delay - Whether to delay test execution
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
delay(delay);
|
||||
|
||||
/**
|
||||
* Forbid exclusive tests (.only)
|
||||
* @param forbidOnly - Whether to forbid .only tests
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
forbidOnly(forbidOnly);
|
||||
|
||||
/**
|
||||
* Forbid pending tests (.skip)
|
||||
* @param forbidPending - Whether to forbid .skip tests
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
forbidPending(forbidPending);
|
||||
|
||||
/**
|
||||
* Show full stack traces
|
||||
* @param fullTrace - Whether to show full stack traces
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
fullTrace(fullTrace);
|
||||
|
||||
/**
|
||||
* Enable colored output
|
||||
* @param color - Whether to enable colored output
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
color(color);
|
||||
|
||||
/**
|
||||
* Show inline diffs
|
||||
* @param inlineDiffs - Whether to show inline diffs
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
inlineDiffs(inlineDiffs);
|
||||
|
||||
/**
|
||||
* Show diff on test failure
|
||||
* @param diff - Whether to show diffs
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
diff(diff);
|
||||
|
||||
/**
|
||||
* Perform dry run (don't execute tests)
|
||||
* @param dryRun - Whether to perform dry run
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
dryRun(dryRun);
|
||||
|
||||
/**
|
||||
* Enable parallel test execution
|
||||
* @param parallel - Whether to run tests in parallel
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
parallelMode(parallel);
|
||||
|
||||
/**
|
||||
* Set root hooks (global setup/teardown)
|
||||
* @param hooks - Root hook functions
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
rootHooks(hooks);
|
||||
|
||||
/**
|
||||
* Set global setup function
|
||||
* @param fn - Global setup function
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
globalSetup(fn);
|
||||
|
||||
/**
|
||||
* Set global teardown function
|
||||
* @param fn - Global teardown function
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
globalTeardown(fn);
|
||||
|
||||
/**
|
||||
* Load test files into memory
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
loadFiles();
|
||||
|
||||
/**
|
||||
* Load test files asynchronously
|
||||
* @returns {Promise<Mocha>} Promise resolving to this instance
|
||||
*/
|
||||
loadFilesAsync();
|
||||
|
||||
/**
|
||||
* Unload test files from memory
|
||||
* @returns {Mocha} this - for chaining
|
||||
*/
|
||||
unloadFiles();
|
||||
|
||||
/**
|
||||
* Run all loaded tests
|
||||
* @param callback - Completion callback receiving failure count
|
||||
* @returns {Runner} Runner instance
|
||||
*/
|
||||
run(callback);
|
||||
|
||||
/**
|
||||
* Dispose of this Mocha instance
|
||||
*/
|
||||
dispose();
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
const Mocha = require('mocha');
|
||||
|
||||
const mocha = new Mocha({
|
||||
ui: 'bdd',
|
||||
reporter: 'spec',
|
||||
timeout: 5000,
|
||||
slow: 100
|
||||
});
|
||||
|
||||
// Add test files
|
||||
mocha.addFile('./test/unit/helpers.js');
|
||||
mocha.addFile('./test/unit/models.js');
|
||||
|
||||
// Configure additional options
|
||||
mocha
|
||||
.grep('User')
|
||||
.bail(true)
|
||||
.checkLeaks(true);
|
||||
|
||||
// Run tests
|
||||
mocha.run(function(failures) {
|
||||
console.log(`Tests completed with ${failures} failures`);
|
||||
process.exitCode = failures ? 1 : 0;
|
||||
});
|
||||
```
|
||||
|
||||
### Runner Class
|
||||
|
||||
Test execution engine that manages the test lifecycle and emits events.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Runner class - manages test execution
|
||||
* Extends EventEmitter for test lifecycle events
|
||||
*/
|
||||
class Runner extends EventEmitter {
|
||||
/**
|
||||
* Run all tests
|
||||
* @param callback - Completion callback
|
||||
* @returns {Runner} this - for chaining
|
||||
*/
|
||||
run(callback);
|
||||
|
||||
/**
|
||||
* Abort test execution
|
||||
* @returns {Runner} this - for chaining
|
||||
*/
|
||||
abort();
|
||||
|
||||
/**
|
||||
* Set grep pattern for filtering tests
|
||||
* @param pattern - String or RegExp pattern
|
||||
* @returns {Runner} this - for chaining
|
||||
*/
|
||||
grep(pattern);
|
||||
|
||||
/**
|
||||
* Get current test count statistics
|
||||
* @returns {Object} Test count statistics
|
||||
*/
|
||||
stats;
|
||||
|
||||
/**
|
||||
* Check if runner is running
|
||||
* @returns {boolean} Whether runner is currently executing
|
||||
*/
|
||||
isRunning();
|
||||
}
|
||||
```
|
||||
|
||||
### Runner Events
|
||||
|
||||
The Runner emits events throughout the test lifecycle that reporters use:
|
||||
|
||||
```javascript { .api }
|
||||
// Test execution lifecycle events
|
||||
const EVENTS = {
|
||||
EVENT_RUN_BEGIN: 'start', // Test run starts
|
||||
EVENT_RUN_END: 'end', // Test run ends
|
||||
EVENT_SUITE_BEGIN: 'suite', // Suite starts
|
||||
EVENT_SUITE_END: 'suite end', // Suite ends
|
||||
EVENT_TEST_BEGIN: 'test', // Individual test starts
|
||||
EVENT_TEST_END: 'test end', // Individual test ends
|
||||
EVENT_TEST_PASS: 'pass', // Test passes
|
||||
EVENT_TEST_FAIL: 'fail', // Test fails
|
||||
EVENT_TEST_PENDING: 'pending', // Test is pending/skipped
|
||||
EVENT_HOOK_BEGIN: 'hook', // Hook starts
|
||||
EVENT_HOOK_END: 'hook end' // Hook ends
|
||||
};
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
const runner = mocha.run();
|
||||
|
||||
runner.on('start', function() {
|
||||
console.log('Test run started');
|
||||
});
|
||||
|
||||
runner.on('pass', function(test) {
|
||||
console.log(`✓ ${test.title}`);
|
||||
});
|
||||
|
||||
runner.on('fail', function(test, err) {
|
||||
console.log(`✗ ${test.title}: ${err.message}`);
|
||||
});
|
||||
|
||||
runner.on('end', function() {
|
||||
console.log('Test run completed');
|
||||
});
|
||||
```
|
||||
|
||||
### Parallel Execution
|
||||
|
||||
Mocha supports parallel test execution for improved performance:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Enable parallel execution
|
||||
* @param options - Parallel execution options
|
||||
*/
|
||||
const mocha = new Mocha({
|
||||
parallel: true,
|
||||
jobs: 4 // Number of worker processes
|
||||
});
|
||||
|
||||
/**
|
||||
* Parallel execution configuration
|
||||
*/
|
||||
interface ParallelOptions {
|
||||
parallel: boolean; // Enable parallel execution
|
||||
jobs?: number; // Number of workers (default: CPU count - 1)
|
||||
timeout?: number; // Worker timeout
|
||||
}
|
||||
```
|
||||
|
||||
### Asynchronous Test Support
|
||||
|
||||
Mocha supports multiple patterns for asynchronous tests:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Test function signatures for different async patterns
|
||||
*/
|
||||
|
||||
// Promise-based tests
|
||||
function testFunction(): Promise<any>;
|
||||
|
||||
// Callback-based tests
|
||||
function testFunction(done: DoneCB): void;
|
||||
|
||||
// Async/await tests
|
||||
async function testFunction(): Promise<any>;
|
||||
|
||||
type DoneCB = (error?: any) => void;
|
||||
```
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
```javascript
|
||||
// Promise-based
|
||||
it('should handle promises', function() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, 100);
|
||||
});
|
||||
});
|
||||
|
||||
// Callback-based
|
||||
it('should handle callbacks', function(done) {
|
||||
setTimeout(() => {
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
// Async/await
|
||||
it('should handle async/await', async function() {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
});
|
||||
```
|
||||
|
||||
### Context and Test State
|
||||
|
||||
Each test receives a context object with utilities:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Test context object (this in test functions)
|
||||
*/
|
||||
interface Context {
|
||||
test?: Test; // Current test object
|
||||
currentTest?: Test; // Alias for test
|
||||
timeout(ms?: number): number | Context; // Set/get timeout
|
||||
slow(ms?: number): number | Context; // Set/get slow threshold
|
||||
skip(): never; // Skip current test
|
||||
retries(count?: number): number | Context; // Set/get retry count
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
it('should use context methods', function() {
|
||||
this.timeout(10000); // Set timeout for this test
|
||||
this.slow(1000); // Set slow threshold
|
||||
|
||||
// Conditionally skip test
|
||||
if (process.env.SKIP_SLOW) {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
// Retry on failure
|
||||
this.retries(3);
|
||||
});
|
||||
```
|
||||
|
||||
### Test File Loading
|
||||
|
||||
Mocha provides methods for loading and managing test files:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Load test files synchronously
|
||||
*/
|
||||
mocha.loadFiles();
|
||||
|
||||
/**
|
||||
* Load test files asynchronously
|
||||
* @returns {Promise<Mocha>} Promise resolving when files are loaded
|
||||
*/
|
||||
mocha.loadFilesAsync();
|
||||
|
||||
/**
|
||||
* Unload test files from require cache
|
||||
*/
|
||||
mocha.unloadFiles();
|
||||
|
||||
/**
|
||||
* Add files to be loaded
|
||||
* @param filepath - Path to test file
|
||||
*/
|
||||
mocha.addFile(filepath);
|
||||
|
||||
/**
|
||||
* Get list of files to be loaded
|
||||
* @returns {string[]} Array of file paths
|
||||
*/
|
||||
mocha.files;
|
||||
```
|
||||
235
.tessl/tiles/tessl/npm-mocha/docs/index.md
Normal file
235
.tessl/tiles/tessl/npm-mocha/docs/index.md
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
# Mocha
|
||||
|
||||
Mocha is a feature-rich JavaScript testing framework that runs on Node.js and in browsers. It provides flexible test organization with BDD/TDD interfaces, extensive reporting options, asynchronous testing support, and parallel execution capabilities for improved performance.
|
||||
|
||||
## Package Information
|
||||
|
||||
- **Package Name**: mocha
|
||||
- **Package Type**: npm
|
||||
- **Language**: JavaScript
|
||||
- **Installation**: `npm install mocha`
|
||||
|
||||
## Core Imports
|
||||
|
||||
```javascript
|
||||
const { Mocha } = require('mocha');
|
||||
const mocha = require('mocha');
|
||||
```
|
||||
|
||||
For ES modules:
|
||||
|
||||
```javascript
|
||||
import Mocha from 'mocha';
|
||||
import { describe, it, before, after, beforeEach, afterEach } from 'mocha';
|
||||
```
|
||||
|
||||
Browser (via script tag):
|
||||
|
||||
```html
|
||||
<script src="node_modules/mocha/mocha.js"></script>
|
||||
<script>
|
||||
mocha.setup('bdd');
|
||||
</script>
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```javascript
|
||||
const { describe, it } = require('mocha');
|
||||
const assert = require('assert');
|
||||
|
||||
describe('Array', function() {
|
||||
describe('#indexOf()', function() {
|
||||
it('should return -1 when the value is not present', function() {
|
||||
assert.equal([1, 2, 3].indexOf(4), -1);
|
||||
});
|
||||
|
||||
it('should return the correct index when value is present', function() {
|
||||
assert.equal([1, 2, 3].indexOf(2), 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Mocha is built around several key components:
|
||||
|
||||
- **Interfaces**: Different styles for writing tests (BDD, TDD, QUnit, Exports)
|
||||
- **Test Organization**: Hierarchical structure with suites and tests
|
||||
- **Execution Engine**: Runner class that manages test execution and events
|
||||
- **Reporting System**: Pluggable reporters for different output formats
|
||||
- **Hook System**: Before/after hooks for setup and teardown at various levels
|
||||
- **Configuration**: Flexible options system supporting files, CLI args, and programmatic setup
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Test Organization and Interfaces
|
||||
|
||||
Mocha supports multiple interfaces for organizing tests, with BDD being the default. Each interface provides different syntax styles for defining test suites and cases.
|
||||
|
||||
```javascript { .api }
|
||||
// BDD Interface (default)
|
||||
function describe(title, fn);
|
||||
function it(title, fn);
|
||||
function before(fn);
|
||||
function after(fn);
|
||||
function beforeEach(fn);
|
||||
function afterEach(fn);
|
||||
|
||||
// TDD Interface
|
||||
function suite(title, fn);
|
||||
function test(title, fn);
|
||||
function setup(fn);
|
||||
function teardown(fn);
|
||||
function suiteSetup(fn);
|
||||
function suiteTeardown(fn);
|
||||
```
|
||||
|
||||
[Test Organization and Interfaces](./interfaces.md)
|
||||
|
||||
### Test Execution and Runner
|
||||
|
||||
Core test execution functionality with lifecycle management, event emission, and parallel execution support.
|
||||
|
||||
```javascript { .api }
|
||||
class Mocha {
|
||||
constructor(options);
|
||||
run(callback);
|
||||
addFile(filepath);
|
||||
reporter(name, options);
|
||||
timeout(ms);
|
||||
slow(ms);
|
||||
}
|
||||
|
||||
class Runner extends EventEmitter {
|
||||
run(callback);
|
||||
abort();
|
||||
grep(pattern);
|
||||
}
|
||||
```
|
||||
|
||||
[Test Execution and Runner](./execution.md)
|
||||
|
||||
### Reporters and Output
|
||||
|
||||
Comprehensive reporting system with built-in reporters and support for custom reporters.
|
||||
|
||||
```javascript { .api }
|
||||
class Base {
|
||||
constructor(runner, options);
|
||||
done(failures, callback);
|
||||
epilogue();
|
||||
}
|
||||
```
|
||||
|
||||
[Reporters and Output](./reporters.md)
|
||||
|
||||
### Browser Support
|
||||
|
||||
Browser-specific functionality and setup for running tests in browser environments.
|
||||
|
||||
```javascript { .api }
|
||||
// Browser global functions
|
||||
mocha.setup(options);
|
||||
mocha.run(callback);
|
||||
mocha.throwError(error);
|
||||
```
|
||||
|
||||
[Browser Support](./browser.md)
|
||||
|
||||
### CLI and Configuration
|
||||
|
||||
Command-line interface and configuration options for test execution.
|
||||
|
||||
```javascript { .api }
|
||||
interface MochaOptions {
|
||||
ui?: string;
|
||||
reporter?: string;
|
||||
timeout?: number;
|
||||
slow?: number;
|
||||
grep?: string | RegExp;
|
||||
fgrep?: string;
|
||||
bail?: boolean;
|
||||
parallel?: boolean;
|
||||
jobs?: number;
|
||||
}
|
||||
```
|
||||
|
||||
[CLI and Configuration](./cli-config.md)
|
||||
|
||||
## Types
|
||||
|
||||
```javascript { .api }
|
||||
interface MochaOptions {
|
||||
ui?: string;
|
||||
reporter?: string | Reporter;
|
||||
timeout?: number;
|
||||
slow?: number;
|
||||
grep?: string | RegExp;
|
||||
fgrep?: string;
|
||||
bail?: boolean;
|
||||
parallel?: boolean;
|
||||
jobs?: number;
|
||||
asyncOnly?: boolean;
|
||||
allowUncaught?: boolean;
|
||||
checkLeaks?: boolean;
|
||||
color?: boolean;
|
||||
delay?: boolean;
|
||||
diff?: boolean;
|
||||
dryRun?: boolean;
|
||||
fullTrace?: boolean;
|
||||
inlineDiffs?: boolean;
|
||||
invert?: boolean;
|
||||
retries?: number;
|
||||
forbidOnly?: boolean;
|
||||
forbidPending?: boolean;
|
||||
global?: string[];
|
||||
recursive?: boolean;
|
||||
sort?: boolean;
|
||||
exit?: boolean;
|
||||
}
|
||||
|
||||
interface Suite {
|
||||
title: string;
|
||||
parent: Suite | null;
|
||||
pending: boolean;
|
||||
timeout(ms?: number): number | Suite;
|
||||
slow(ms?: number): number | Suite;
|
||||
bail(bail?: boolean): boolean | Suite;
|
||||
}
|
||||
|
||||
interface Test {
|
||||
title: string;
|
||||
fn: Function;
|
||||
parent: Suite;
|
||||
pending: boolean;
|
||||
state: 'failed' | 'passed' | 'pending';
|
||||
timeout(ms?: number): number | Test;
|
||||
slow(ms?: number): number | Test;
|
||||
}
|
||||
|
||||
interface Hook {
|
||||
title: string;
|
||||
fn: Function;
|
||||
parent: Suite;
|
||||
type: 'before' | 'after' | 'beforeEach' | 'afterEach';
|
||||
}
|
||||
|
||||
interface Context {
|
||||
test?: Test;
|
||||
currentTest?: Test;
|
||||
timeout(ms?: number): number | Context;
|
||||
slow(ms?: number): number | Context;
|
||||
skip(): never;
|
||||
retries(count?: number): number | Context;
|
||||
}
|
||||
|
||||
type DoneCB = (error?: any) => void;
|
||||
type AsyncTestFunction = () => Promise<any>;
|
||||
type TestFunction = (done?: DoneCB) => void | Promise<any>;
|
||||
|
||||
interface Reporter {
|
||||
new(runner: Runner, options?: any): Reporter;
|
||||
}
|
||||
```
|
||||
356
.tessl/tiles/tessl/npm-mocha/docs/interfaces.md
Normal file
356
.tessl/tiles/tessl/npm-mocha/docs/interfaces.md
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
# Test Organization and Interfaces
|
||||
|
||||
Mocha supports multiple interfaces for organizing and writing tests. Each interface provides a different syntax style and mental model for structuring test suites and cases.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### BDD Interface (Default)
|
||||
|
||||
Behavior Driven Development interface using `describe` and `it` functions. This is the default interface and most commonly used.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Define a test suite
|
||||
* @param title - Suite title/description
|
||||
* @param fn - Suite implementation function
|
||||
*/
|
||||
function describe(title, fn);
|
||||
|
||||
/**
|
||||
* Define a test case
|
||||
* @param title - Test title/description
|
||||
* @param fn - Test implementation function
|
||||
*/
|
||||
function it(title, fn);
|
||||
|
||||
/**
|
||||
* Define aliases for describe and it
|
||||
*/
|
||||
function context(title, fn); // alias for describe
|
||||
function specify(title, fn); // alias for it
|
||||
|
||||
/**
|
||||
* Define hooks that run before/after suites and tests
|
||||
*/
|
||||
function before(fn); // runs once before all tests in suite
|
||||
function after(fn); // runs once after all tests in suite
|
||||
function beforeEach(fn); // runs before each test
|
||||
function afterEach(fn); // runs after each test
|
||||
|
||||
/**
|
||||
* Exclusive execution - only run marked tests/suites
|
||||
*/
|
||||
function describe.only(title, fn);
|
||||
function it.only(title, fn);
|
||||
function context.only(title, fn);
|
||||
function specify.only(title, fn);
|
||||
|
||||
/**
|
||||
* Skip tests/suites - do not execute
|
||||
*/
|
||||
function describe.skip(title, fn);
|
||||
function it.skip(title, fn);
|
||||
function context.skip(title, fn);
|
||||
function specify.skip(title, fn);
|
||||
|
||||
/**
|
||||
* Skip aliases using x prefix
|
||||
*/
|
||||
function xdescribe(title, fn); // alias for describe.skip
|
||||
function xit(title, fn); // alias for it.skip
|
||||
function xcontext(title, fn); // alias for context.skip
|
||||
function xspecify(title, fn); // alias for specify.skip
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
const assert = require('assert');
|
||||
|
||||
describe('Calculator', function() {
|
||||
let calculator;
|
||||
|
||||
before(function() {
|
||||
// Setup before all tests
|
||||
calculator = new Calculator();
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
// Reset state before each test
|
||||
calculator.reset();
|
||||
});
|
||||
|
||||
describe('#add()', function() {
|
||||
it('should add two positive numbers', function() {
|
||||
const result = calculator.add(2, 3);
|
||||
assert.equal(result, 5);
|
||||
});
|
||||
|
||||
it('should handle negative numbers', function() {
|
||||
const result = calculator.add(-1, 1);
|
||||
assert.equal(result, 0);
|
||||
});
|
||||
|
||||
it.skip('should handle decimal numbers', function() {
|
||||
// This test is skipped
|
||||
});
|
||||
});
|
||||
|
||||
describe.only('#multiply()', function() {
|
||||
// Only this suite will run when using .only
|
||||
it('should multiply two numbers', function() {
|
||||
const result = calculator.multiply(3, 4);
|
||||
assert.equal(result, 12);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### TDD Interface
|
||||
|
||||
Test Driven Development interface using `suite` and `test` functions.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Define a test suite (equivalent to describe)
|
||||
* @param title - Suite title/description
|
||||
* @param fn - Suite implementation function
|
||||
*/
|
||||
function suite(title, fn);
|
||||
|
||||
/**
|
||||
* Define a test case (equivalent to it)
|
||||
* @param title - Test title/description
|
||||
* @param fn - Test implementation function
|
||||
*/
|
||||
function test(title, fn);
|
||||
|
||||
/**
|
||||
* Define hooks for setup and teardown
|
||||
*/
|
||||
function setup(fn); // equivalent to beforeEach
|
||||
function teardown(fn); // equivalent to afterEach
|
||||
function suiteSetup(fn); // equivalent to before
|
||||
function suiteTeardown(fn); // equivalent to after
|
||||
|
||||
/**
|
||||
* Exclusive execution modifiers
|
||||
*/
|
||||
function suite.only(title, fn);
|
||||
function test.only(title, fn);
|
||||
|
||||
/**
|
||||
* Skip modifiers
|
||||
*/
|
||||
function suite.skip(title, fn);
|
||||
function test.skip(title, fn);
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
const assert = require('assert');
|
||||
|
||||
suite('Calculator TDD', function() {
|
||||
let calculator;
|
||||
|
||||
suiteSetup(function() {
|
||||
calculator = new Calculator();
|
||||
});
|
||||
|
||||
setup(function() {
|
||||
calculator.reset();
|
||||
});
|
||||
|
||||
suite('Addition', function() {
|
||||
test('should add positive numbers', function() {
|
||||
const result = calculator.add(2, 3);
|
||||
assert.equal(result, 5);
|
||||
});
|
||||
|
||||
test('should add negative numbers', function() {
|
||||
const result = calculator.add(-2, -3);
|
||||
assert.equal(result, -5);
|
||||
});
|
||||
});
|
||||
|
||||
teardown(function() {
|
||||
// Cleanup after each test
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### QUnit Interface
|
||||
|
||||
QUnit-style interface providing `suite` and `test` functions with QUnit-compatible hooks.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Define a test suite
|
||||
* @param title - Suite title/description
|
||||
* @param fn - Suite implementation function
|
||||
*/
|
||||
function suite(title, fn);
|
||||
|
||||
/**
|
||||
* Define a test case
|
||||
* @param title - Test title/description
|
||||
* @param fn - Test implementation function
|
||||
*/
|
||||
function test(title, fn);
|
||||
|
||||
/**
|
||||
* Define hooks
|
||||
*/
|
||||
function before(fn); // runs before all tests in suite
|
||||
function after(fn); // runs after all tests in suite
|
||||
function beforeEach(fn); // runs before each test
|
||||
function afterEach(fn); // runs after each test
|
||||
|
||||
/**
|
||||
* Exclusive and skip modifiers
|
||||
*/
|
||||
function suite.only(title, fn);
|
||||
function test.only(title, fn);
|
||||
function suite.skip(title, fn);
|
||||
function test.skip(title, fn);
|
||||
```
|
||||
|
||||
### Exports Interface
|
||||
|
||||
Node.js module.exports style interface where test structure is defined using object properties.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Exports interface uses object properties to define test structure
|
||||
* No global functions - tests are defined as object methods
|
||||
*/
|
||||
|
||||
// Example structure:
|
||||
module.exports = {
|
||||
'Calculator': {
|
||||
'before': function() {
|
||||
// Setup
|
||||
},
|
||||
|
||||
'#add()': {
|
||||
'should add positive numbers': function() {
|
||||
// Test implementation
|
||||
},
|
||||
|
||||
'should add negative numbers': function() {
|
||||
// Test implementation
|
||||
}
|
||||
},
|
||||
|
||||
'#multiply()': {
|
||||
'should multiply numbers': function() {
|
||||
// Test implementation
|
||||
}
|
||||
},
|
||||
|
||||
'after': function() {
|
||||
// Teardown
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```javascript
|
||||
const assert = require('assert');
|
||||
const Calculator = require('./calculator');
|
||||
|
||||
module.exports = {
|
||||
'Calculator Tests': {
|
||||
before: function() {
|
||||
this.calculator = new Calculator();
|
||||
},
|
||||
|
||||
'Addition Tests': {
|
||||
beforeEach: function() {
|
||||
this.calculator.reset();
|
||||
},
|
||||
|
||||
'should add two positive numbers': function() {
|
||||
const result = this.calculator.add(2, 3);
|
||||
assert.equal(result, 5);
|
||||
},
|
||||
|
||||
'should handle zero': function() {
|
||||
const result = this.calculator.add(5, 0);
|
||||
assert.equal(result, 5);
|
||||
}
|
||||
},
|
||||
|
||||
'Multiplication Tests': {
|
||||
'should multiply positive numbers': function() {
|
||||
const result = this.calculator.multiply(3, 4);
|
||||
assert.equal(result, 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Interface Selection
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Set the interface for a Mocha instance or globally
|
||||
* @param name - Interface name: 'bdd', 'tdd', 'qunit', 'exports'
|
||||
*/
|
||||
mocha.ui(name);
|
||||
|
||||
// Available interfaces
|
||||
const interfaces = {
|
||||
bdd: require('mocha/lib/interfaces/bdd'),
|
||||
tdd: require('mocha/lib/interfaces/tdd'),
|
||||
qunit: require('mocha/lib/interfaces/qunit'),
|
||||
exports: require('mocha/lib/interfaces/exports')
|
||||
};
|
||||
```
|
||||
|
||||
### Global Function Aliases
|
||||
|
||||
All interfaces provide these global function aliases for compatibility:
|
||||
|
||||
```javascript { .api }
|
||||
// These functions delegate to the current interface
|
||||
function describe(title, fn); // maps to current interface's suite function
|
||||
function it(title, fn); // maps to current interface's test function
|
||||
function before(fn); // maps to current interface's before hook
|
||||
function after(fn); // maps to current interface's after hook
|
||||
function beforeEach(fn); // maps to current interface's beforeEach hook
|
||||
function afterEach(fn); // maps to current interface's afterEach hook
|
||||
|
||||
// TDD aliases (always available)
|
||||
function suite(title, fn); // alias for describe
|
||||
function test(title, fn); // alias for it
|
||||
function setup(fn); // alias for beforeEach
|
||||
function teardown(fn); // alias for afterEach
|
||||
function suiteSetup(fn); // alias for before
|
||||
function suiteTeardown(fn); // alias for after
|
||||
|
||||
// Skip aliases
|
||||
function xdescribe(title, fn); // alias for describe.skip
|
||||
function xit(title, fn); // alias for it.skip
|
||||
|
||||
// Programmatic execution
|
||||
function run(); // trigger test execution
|
||||
```
|
||||
|
||||
### Interface Configuration
|
||||
|
||||
Interfaces can be configured when creating a Mocha instance:
|
||||
|
||||
```javascript
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd', // Use TDD interface
|
||||
// other options...
|
||||
});
|
||||
|
||||
// Or set programmatically
|
||||
mocha.ui('bdd');
|
||||
```
|
||||
530
.tessl/tiles/tessl/npm-mocha/docs/reporters.md
Normal file
530
.tessl/tiles/tessl/npm-mocha/docs/reporters.md
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
# Reporters and Output
|
||||
|
||||
Comprehensive reporting system with built-in reporters for various output formats and support for custom reporters. Reporters listen to Runner events and format test results.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Base Reporter Class
|
||||
|
||||
Foundation class for all reporters providing shared functionality.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Base reporter class that all reporters extend
|
||||
* @param runner - Runner instance that emits test events
|
||||
* @param options - Reporter-specific options
|
||||
*/
|
||||
class Base {
|
||||
constructor(runner, options);
|
||||
|
||||
/**
|
||||
* Called when test run completes
|
||||
* @param failures - Number of failed tests
|
||||
* @param callback - Completion callback
|
||||
*/
|
||||
done(failures, callback);
|
||||
|
||||
/**
|
||||
* Output test run summary/epilogue
|
||||
*/
|
||||
epilogue();
|
||||
|
||||
/**
|
||||
* Get test statistics
|
||||
* @returns {Object} Statistics object
|
||||
*/
|
||||
stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistics object structure
|
||||
*/
|
||||
interface Stats {
|
||||
suites: number; // Number of suites
|
||||
tests: number; // Total number of tests
|
||||
passes: number; // Number of passing tests
|
||||
pending: number; // Number of pending tests
|
||||
failures: number; // Number of failing tests
|
||||
duration: number; // Total execution time in ms
|
||||
start: Date; // Test run start time
|
||||
end: Date; // Test run end time
|
||||
}
|
||||
```
|
||||
|
||||
### Built-in Reporters
|
||||
|
||||
#### Spec Reporter (Default)
|
||||
|
||||
Hierarchical output showing test structure and results.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Spec reporter - hierarchical test output
|
||||
*/
|
||||
class Spec extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
Calculator
|
||||
#add()
|
||||
✓ should add positive numbers
|
||||
✓ should handle negative numbers
|
||||
- should handle decimals (pending)
|
||||
#multiply()
|
||||
✓ should multiply numbers
|
||||
1) should handle zero
|
||||
|
||||
1) Calculator #multiply() should handle zero:
|
||||
Error: Expected 0 but got NaN
|
||||
```
|
||||
|
||||
#### Dot Reporter
|
||||
|
||||
Minimal dot-based progress output.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Dot reporter - minimal dot progress
|
||||
*/
|
||||
class Dot extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
..·..
|
||||
|
||||
4 passing (12ms)
|
||||
1 pending
|
||||
```
|
||||
|
||||
#### TAP Reporter
|
||||
|
||||
Test Anything Protocol output.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* TAP reporter - Test Anything Protocol format
|
||||
*/
|
||||
class TAP extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
1..5
|
||||
ok 1 Calculator #add() should add positive numbers
|
||||
ok 2 Calculator #add() should handle negative numbers
|
||||
ok 3 Calculator #multiply() should multiply numbers # SKIP
|
||||
not ok 4 Calculator #multiply() should handle zero
|
||||
---
|
||||
message: Expected 0 but got NaN
|
||||
severity: fail
|
||||
...
|
||||
```
|
||||
|
||||
#### JSON Reporter
|
||||
|
||||
Machine-readable JSON output.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* JSON reporter - structured JSON output
|
||||
*/
|
||||
class JSON extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### HTML Reporter (Browser)
|
||||
|
||||
Browser-specific HTML output with interactive features.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* HTML reporter - browser HTML output with DOM integration
|
||||
* Only available in browser environments
|
||||
*/
|
||||
class HTML extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### List Reporter
|
||||
|
||||
Simple list format showing all tests.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* List reporter - simple list of all tests
|
||||
*/
|
||||
class List extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### Min Reporter
|
||||
|
||||
Minimal output showing only summary.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Min reporter - minimal summary output
|
||||
*/
|
||||
class Min extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### Nyan Reporter
|
||||
|
||||
Colorful Nyan Cat progress reporter.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Nyan reporter - colorful cat progress animation
|
||||
*/
|
||||
class Nyan extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### XUnit Reporter
|
||||
|
||||
XML output compatible with JUnit/xUnit format.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* XUnit reporter - XML output for CI systems
|
||||
*/
|
||||
class XUnit extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### Progress Reporter
|
||||
|
||||
Progress bar with test count information.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Progress reporter - progress bar with counters
|
||||
*/
|
||||
class Progress extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### Landing Reporter
|
||||
|
||||
Landing strip style progress indicator.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Landing reporter - landing strip progress
|
||||
*/
|
||||
class Landing extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
#### JSON Stream Reporter
|
||||
|
||||
Streaming JSON output for real-time processing.
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* JSONStream reporter - streaming JSON events
|
||||
*/
|
||||
class JSONStream extends Base {
|
||||
constructor(runner, options);
|
||||
}
|
||||
```
|
||||
|
||||
### Reporter Selection and Configuration
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Set reporter for a Mocha instance
|
||||
* @param name - Reporter name or constructor function
|
||||
* @param options - Reporter-specific options
|
||||
*/
|
||||
mocha.reporter(name, options);
|
||||
|
||||
/**
|
||||
* Available built-in reporters
|
||||
*/
|
||||
const reporters = {
|
||||
Base: Base,
|
||||
base: Base,
|
||||
Dot: Dot,
|
||||
dot: Dot,
|
||||
Doc: Doc,
|
||||
doc: Doc,
|
||||
TAP: TAP,
|
||||
tap: TAP,
|
||||
JSON: JSON,
|
||||
json: JSON,
|
||||
HTML: HTML,
|
||||
html: HTML,
|
||||
List: List,
|
||||
list: List,
|
||||
Min: Min,
|
||||
min: Min,
|
||||
Spec: Spec,
|
||||
spec: Spec,
|
||||
Nyan: Nyan,
|
||||
nyan: Nyan,
|
||||
XUnit: XUnit,
|
||||
xunit: XUnit,
|
||||
Markdown: Markdown,
|
||||
markdown: Markdown,
|
||||
Progress: Progress,
|
||||
progress: Progress,
|
||||
Landing: Landing,
|
||||
landing: Landing,
|
||||
JSONStream: JSONStream,
|
||||
'json-stream': JSONStream
|
||||
};
|
||||
```
|
||||
|
||||
**Usage Examples:**
|
||||
|
||||
```javascript
|
||||
// Using built-in reporter by name
|
||||
const mocha = new Mocha({
|
||||
reporter: 'spec'
|
||||
});
|
||||
|
||||
// With reporter options
|
||||
mocha.reporter('xunit', {
|
||||
output: './test-results.xml'
|
||||
});
|
||||
|
||||
// Using reporter constructor
|
||||
const CustomReporter = require('./custom-reporter');
|
||||
mocha.reporter(CustomReporter);
|
||||
|
||||
// Programmatically
|
||||
mocha.reporter('json').reporter('tap'); // Last one wins
|
||||
```
|
||||
|
||||
### Custom Reporters
|
||||
|
||||
Create custom reporters by extending the Base class:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Custom reporter implementation
|
||||
*/
|
||||
class CustomReporter extends Base {
|
||||
constructor(runner, options) {
|
||||
super(runner, options);
|
||||
|
||||
// Listen to runner events
|
||||
runner.on('start', () => {
|
||||
console.log('Tests starting...');
|
||||
});
|
||||
|
||||
runner.on('pass', (test) => {
|
||||
console.log(`✓ ${test.fullTitle()}`);
|
||||
});
|
||||
|
||||
runner.on('fail', (test, err) => {
|
||||
console.log(`✗ ${test.fullTitle()}: ${err.message}`);
|
||||
});
|
||||
|
||||
runner.on('end', () => {
|
||||
this.epilogue();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reporter Events and Data
|
||||
|
||||
Reporters receive these events with associated data:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Runner events available to reporters
|
||||
*/
|
||||
const events = [
|
||||
'start', // Test run begins
|
||||
'end', // Test run ends
|
||||
'suite', // Suite begins
|
||||
'suite end', // Suite ends
|
||||
'test', // Test begins
|
||||
'test end', // Test ends
|
||||
'pass', // Test passes
|
||||
'fail', // Test fails
|
||||
'pending', // Test is pending
|
||||
'hook', // Hook begins
|
||||
'hook end' // Hook ends
|
||||
];
|
||||
|
||||
/**
|
||||
* Test object structure passed to reporter events
|
||||
*/
|
||||
interface Test {
|
||||
title: string; // Test title
|
||||
fullTitle(): string; // Full hierarchical title
|
||||
duration: number; // Test execution time
|
||||
state: 'passed' | 'failed' | 'pending';
|
||||
err?: Error; // Error if test failed
|
||||
parent: Suite; // Parent suite
|
||||
pending: boolean; // Whether test is pending
|
||||
timeout(): number; // Test timeout value
|
||||
slow(): number; // Test slow threshold
|
||||
}
|
||||
|
||||
/**
|
||||
* Suite object structure
|
||||
*/
|
||||
interface Suite {
|
||||
title: string; // Suite title
|
||||
fullTitle(): string; // Full hierarchical title
|
||||
parent?: Suite; // Parent suite
|
||||
tests: Test[]; // Child tests
|
||||
suites: Suite[]; // Child suites
|
||||
pending: boolean; // Whether suite is pending
|
||||
timeout(): number; // Suite timeout value
|
||||
slow(): number; // Suite slow threshold
|
||||
}
|
||||
```
|
||||
|
||||
### Reporter Utilities
|
||||
|
||||
Base reporter provides utility methods:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Utility methods available in Base reporter
|
||||
*/
|
||||
class Base {
|
||||
/**
|
||||
* Get color function for terminal output
|
||||
* @param name - Color name
|
||||
* @returns {Function} Color function
|
||||
*/
|
||||
color(name);
|
||||
|
||||
/**
|
||||
* Generate cursor movement for terminal
|
||||
* @returns {Object} Cursor utilities
|
||||
*/
|
||||
cursor;
|
||||
|
||||
/**
|
||||
* Check if output supports color
|
||||
* @returns {boolean} Whether colors are supported
|
||||
*/
|
||||
useColors;
|
||||
|
||||
/**
|
||||
* Get window size for formatting
|
||||
* @returns {Object} Window dimensions
|
||||
*/
|
||||
window;
|
||||
|
||||
/**
|
||||
* Get symbols for different output types
|
||||
* @returns {Object} Symbol definitions
|
||||
*/
|
||||
symbols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Available color names
|
||||
*/
|
||||
const colors = [
|
||||
'pass', // Green
|
||||
'fail', // Red
|
||||
'bright pass', // Bright green
|
||||
'bright fail', // Bright red
|
||||
'bright yellow', // Bright yellow
|
||||
'pending', // Cyan
|
||||
'suite', // Blue
|
||||
'error title', // Red background
|
||||
'error message', // Red text
|
||||
'error stack', // Gray
|
||||
'checkmark', // Green
|
||||
'fast', // Gray
|
||||
'medium', // Yellow
|
||||
'slow', // Red
|
||||
'green', // Green
|
||||
'light', // Gray
|
||||
'diff gutter', // Gray
|
||||
'diff added', // Green
|
||||
'diff removed' // Red
|
||||
];
|
||||
```
|
||||
|
||||
### Reporter Configuration Options
|
||||
|
||||
Different reporters accept various configuration options:
|
||||
|
||||
```javascript { .api }
|
||||
/**
|
||||
* Common reporter options
|
||||
*/
|
||||
interface ReporterOptions {
|
||||
output?: string; // Output file path
|
||||
reporterOptions?: any; // Reporter-specific options
|
||||
}
|
||||
|
||||
/**
|
||||
* XUnit reporter specific options
|
||||
*/
|
||||
interface XUnitOptions {
|
||||
output?: string; // XML output file
|
||||
suiteName?: string; // Test suite name in XML
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON reporter specific options
|
||||
*/
|
||||
interface JSONOptions {
|
||||
output?: string; // JSON output file
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML reporter specific options
|
||||
*/
|
||||
interface HTMLOptions {
|
||||
inline?: boolean; // Inline CSS/JS
|
||||
timeout?: number; // Test timeout
|
||||
}
|
||||
```
|
||||
|
||||
**Configuration Examples:**
|
||||
|
||||
```javascript
|
||||
// XUnit with file output
|
||||
mocha.reporter('xunit', {
|
||||
reporterOptions: {
|
||||
output: './test-results.xml',
|
||||
suiteName: 'My Test Suite'
|
||||
}
|
||||
});
|
||||
|
||||
// JSON with custom formatting
|
||||
mocha.reporter('json', {
|
||||
reporterOptions: {
|
||||
output: './results.json'
|
||||
}
|
||||
});
|
||||
|
||||
// Multiple reporters (using third-party libraries)
|
||||
const MultiReporter = require('mocha-multi-reporters');
|
||||
mocha.reporter(MultiReporter, {
|
||||
reporterOptions: {
|
||||
configFile: './reporter-config.json'
|
||||
}
|
||||
});
|
||||
```
|
||||
7
.tessl/tiles/tessl/npm-mocha/tile.json
Normal file
7
.tessl/tiles/tessl/npm-mocha/tile.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "tessl/npm-mocha",
|
||||
"version": "11.7.0",
|
||||
"docs": "docs/index.md",
|
||||
"describes": "pkg:npm/mocha@11.7.2",
|
||||
"summary": "Simple, flexible, fun JavaScript testing framework for Node.js and browsers"
|
||||
}
|
||||
640
.tessl/tiles/tessl/npm-typescript/docs/ast/factory.md
Normal file
640
.tessl/tiles/tessl/npm-typescript/docs/ast/factory.md
Normal file
|
|
@ -0,0 +1,640 @@
|
|||
# Node Factory
|
||||
|
||||
Factory functions for creating and updating AST nodes programmatically. The `factory` constant provides 300+ methods for building complete TypeScript AST structures.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Factory Constant
|
||||
|
||||
```typescript { .api }
|
||||
const factory: NodeFactory;
|
||||
```
|
||||
|
||||
### Node Factory Interface
|
||||
|
||||
Core factory methods for AST node creation.
|
||||
|
||||
```typescript { .api }
|
||||
interface NodeFactory {
|
||||
/* Literals */
|
||||
createNumericLiteral(value: string | number, numericLiteralFlags?: TokenFlags): NumericLiteral;
|
||||
createBigIntLiteral(value: string | PseudoBigInt): BigIntLiteral;
|
||||
createStringLiteral(text: string, isSingleQuote?: boolean): StringLiteral;
|
||||
createStringLiteralFromNode(sourceNode: PropertyNameLiteral | PrivateIdentifier, isSingleQuote?: boolean): StringLiteral;
|
||||
createRegularExpressionLiteral(text: string): RegularExpressionLiteral;
|
||||
|
||||
/* Identifiers */
|
||||
createIdentifier(text: string): Identifier;
|
||||
createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean): Identifier;
|
||||
createLoopVariable(reservedInNestedScopes?: boolean): Identifier;
|
||||
createUniqueName(text: string, flags?: GeneratedIdentifierFlags): Identifier;
|
||||
getGeneratedNameForNode(node: Node | undefined, flags?: GeneratedIdentifierFlags): Identifier;
|
||||
createPrivateIdentifier(text: string): PrivateIdentifier;
|
||||
createUniquePrivateName(text?: string): PrivateIdentifier;
|
||||
|
||||
/* Punctuation */
|
||||
createToken<TKind extends PunctuationSyntaxKind>(token: TKind): PunctuationToken<TKind>;
|
||||
createSuper(): SuperExpression;
|
||||
createThis(): ThisExpression;
|
||||
createNull(): NullLiteral;
|
||||
createTrue(): TrueLiteral;
|
||||
createFalse(): FalseLiteral;
|
||||
|
||||
/* Modifiers */
|
||||
createModifier<T extends ModifierSyntaxKind>(kind: T): ModifierToken<T>;
|
||||
createModifiersFromModifierFlags(flags: ModifierFlags): Modifier[] | undefined;
|
||||
|
||||
/* QualifiedName */
|
||||
createQualifiedName(left: EntityName, right: string | Identifier): QualifiedName;
|
||||
updateQualifiedName(node: QualifiedName, left: EntityName, right: Identifier): QualifiedName;
|
||||
|
||||
/* Computed Property Name */
|
||||
createComputedPropertyName(expression: Expression): ComputedPropertyName;
|
||||
updateComputedPropertyName(node: ComputedPropertyName, expression: Expression): ComputedPropertyName;
|
||||
|
||||
/* Type Parameters */
|
||||
createTypeParameterDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode): TypeParameterDeclaration;
|
||||
updateTypeParameterDeclaration(node: TypeParameterDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined): TypeParameterDeclaration;
|
||||
|
||||
/* Parameters */
|
||||
createParameterDeclaration(modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression): ParameterDeclaration;
|
||||
updateParameterDeclaration(node: ParameterDeclaration, modifiers: readonly ModifierLike[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): ParameterDeclaration;
|
||||
|
||||
/* Decorators */
|
||||
createDecorator(expression: Expression): Decorator;
|
||||
updateDecorator(node: Decorator, expression: Expression): Decorator;
|
||||
|
||||
/* Type Nodes */
|
||||
createKeywordTypeNode<TKind extends KeywordTypeSyntaxKind>(kind: TKind): KeywordTypeNode<TKind>;
|
||||
|
||||
createTypeReferenceNode(typeName: string | EntityName, typeArguments?: readonly TypeNode[]): TypeReferenceNode;
|
||||
updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray<TypeNode> | undefined): TypeReferenceNode;
|
||||
|
||||
createFunctionTypeNode(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): FunctionTypeNode;
|
||||
updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode): FunctionTypeNode;
|
||||
|
||||
createConstructorTypeNode(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): ConstructorTypeNode;
|
||||
updateConstructorTypeNode(node: ConstructorTypeNode, modifiers: readonly Modifier[] | undefined, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode): ConstructorTypeNode;
|
||||
|
||||
createTypeQueryNode(exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode;
|
||||
updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName, typeArguments?: readonly TypeNode[]): TypeQueryNode;
|
||||
|
||||
createTypeLiteralNode(members: readonly TypeElement[] | undefined): TypeLiteralNode;
|
||||
updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray<TypeElement>): TypeLiteralNode;
|
||||
|
||||
createArrayTypeNode(elementType: TypeNode): ArrayTypeNode;
|
||||
updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode;
|
||||
|
||||
createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode;
|
||||
updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode;
|
||||
|
||||
createUnionTypeNode(types: readonly TypeNode[]): UnionTypeNode;
|
||||
updateUnionTypeNode(node: UnionTypeNode, types: NodeArray<TypeNode>): UnionTypeNode;
|
||||
|
||||
createIntersectionTypeNode(types: readonly TypeNode[]): IntersectionTypeNode;
|
||||
updateIntersectionTypeNode(node: IntersectionTypeNode, types: NodeArray<TypeNode>): IntersectionTypeNode;
|
||||
|
||||
createConditionalTypeNode(checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode;
|
||||
updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode;
|
||||
|
||||
createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode;
|
||||
updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode;
|
||||
|
||||
createMappedTypeNode(readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray<TypeElement> | undefined): MappedTypeNode;
|
||||
updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyKeyword | PlusToken | MinusToken | undefined, typeParameter: TypeParameterDeclaration, nameType: TypeNode | undefined, questionToken: QuestionToken | PlusToken | MinusToken | undefined, type: TypeNode | undefined, members: NodeArray<TypeElement> | undefined): MappedTypeNode;
|
||||
|
||||
createLiteralTypeNode(literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
updateLiteralTypeNode(node: LiteralTypeNode, literal: LiteralTypeNode["literal"]): LiteralTypeNode;
|
||||
|
||||
/* Expressions */
|
||||
createObjectLiteralExpression(properties?: readonly ObjectLiteralElementLike[], multiLine?: boolean): ObjectLiteralExpression;
|
||||
updateObjectLiteralExpression(node: ObjectLiteralExpression, properties: readonly ObjectLiteralElementLike[]): ObjectLiteralExpression;
|
||||
|
||||
createPropertyAccessExpression(expression: Expression, name: string | Identifier | PrivateIdentifier): PropertyAccessExpression;
|
||||
updatePropertyAccessExpression(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier): PropertyAccessExpression;
|
||||
|
||||
createPropertyAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, name: string | Identifier | PrivateIdentifier): PropertyAccessChain;
|
||||
updatePropertyAccessChain(node: PropertyAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, name: Identifier | PrivateIdentifier): PropertyAccessChain;
|
||||
|
||||
createElementAccessExpression(expression: Expression, index: number | Expression): ElementAccessExpression;
|
||||
updateElementAccessExpression(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression): ElementAccessExpression;
|
||||
|
||||
createCallExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallExpression;
|
||||
updateCallExpression(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallExpression;
|
||||
|
||||
createNewExpression(expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
|
||||
updateNewExpression(node: NewExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): NewExpression;
|
||||
|
||||
createTaggedTemplateExpression(tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression;
|
||||
updateTaggedTemplateExpression(node: TaggedTemplateExpression, tag: Expression, typeArguments: readonly TypeNode[] | undefined, template: TemplateLiteral): TaggedTemplateExpression;
|
||||
|
||||
createTypeAssertion(type: TypeNode, expression: Expression): TypeAssertion;
|
||||
updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression): TypeAssertion;
|
||||
|
||||
createParenthesizedExpression(expression: Expression): ParenthesizedExpression;
|
||||
updateParenthesizedExpression(node: ParenthesizedExpression, expression: Expression): ParenthesizedExpression;
|
||||
|
||||
createFunctionExpression(modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[] | undefined, type: TypeNode | undefined, body: Block): FunctionExpression;
|
||||
updateFunctionExpression(node: FunctionExpression, modifiers: readonly Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block): FunctionExpression;
|
||||
|
||||
createArrowFunction(modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
|
||||
updateArrowFunction(node: ArrowFunction, modifiers: readonly Modifier[] | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken, body: ConciseBody): ArrowFunction;
|
||||
|
||||
createDeleteExpression(expression: Expression): DeleteExpression;
|
||||
updateDeleteExpression(node: DeleteExpression, expression: Expression): DeleteExpression;
|
||||
|
||||
createTypeOfExpression(expression: Expression): TypeOfExpression;
|
||||
updateTypeOfExpression(node: TypeOfExpression, expression: Expression): TypeOfExpression;
|
||||
|
||||
createVoidExpression(expression: Expression): VoidExpression;
|
||||
updateVoidExpression(node: VoidExpression, expression: Expression): VoidExpression;
|
||||
|
||||
createAwaitExpression(expression: Expression): AwaitExpression;
|
||||
updateAwaitExpression(node: AwaitExpression, expression: Expression): AwaitExpression;
|
||||
|
||||
createPrefixUnaryExpression(operator: PrefixUnaryOperator, operand: Expression): PrefixUnaryExpression;
|
||||
updatePrefixUnaryExpression(node: PrefixUnaryExpression, operand: Expression): PrefixUnaryExpression;
|
||||
|
||||
createPostfixUnaryExpression(operand: Expression, operator: PostfixUnaryOperator): PostfixUnaryExpression;
|
||||
updatePostfixUnaryExpression(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression;
|
||||
|
||||
createBinaryExpression(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression;
|
||||
updateBinaryExpression(node: BinaryExpression, left: Expression, operator: BinaryOperatorToken, right: Expression): BinaryExpression;
|
||||
|
||||
createConditionalExpression(condition: Expression, questionToken: QuestionToken | undefined, whenTrue: Expression, colonToken: ColonToken | undefined, whenFalse: Expression): ConditionalExpression;
|
||||
updateConditionalExpression(node: ConditionalExpression, condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
|
||||
|
||||
createArrayLiteralExpression(elements?: readonly Expression[], multiLine?: boolean): ArrayLiteralExpression;
|
||||
updateArrayLiteralExpression(node: ArrayLiteralExpression, elements: readonly Expression[]): ArrayLiteralExpression;
|
||||
|
||||
createSpreadElement(expression: Expression): SpreadElement;
|
||||
updateSpreadElement(node: SpreadElement, expression: Expression): SpreadElement;
|
||||
|
||||
createClassExpression(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression;
|
||||
updateClassExpression(node: ClassExpression, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassExpression;
|
||||
|
||||
createAsExpression(expression: Expression, type: TypeNode): AsExpression;
|
||||
updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode): AsExpression;
|
||||
|
||||
createNonNullExpression(expression: Expression): NonNullExpression;
|
||||
updateNonNullExpression(node: NonNullExpression, expression: Expression): NonNullExpression;
|
||||
|
||||
createSatisfiesExpression(expression: Expression, type: TypeNode): SatisfiesExpression;
|
||||
updateSatisfiesExpression(node: SatisfiesExpression, expression: Expression, type: TypeNode): SatisfiesExpression;
|
||||
|
||||
/* Statements */
|
||||
createBlock(statements: readonly Statement[], multiLine?: boolean): Block;
|
||||
updateBlock(node: Block, statements: readonly Statement[]): Block;
|
||||
|
||||
createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList | readonly VariableDeclaration[]): VariableStatement;
|
||||
updateVariableStatement(node: VariableStatement, modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList): VariableStatement;
|
||||
|
||||
createEmptyStatement(): EmptyStatement;
|
||||
|
||||
createExpressionStatement(expression: Expression): ExpressionStatement;
|
||||
updateExpressionStatement(node: ExpressionStatement, expression: Expression): ExpressionStatement;
|
||||
|
||||
createIfStatement(expression: Expression, thenStatement: Statement, elseStatement?: Statement): IfStatement;
|
||||
updateIfStatement(node: IfStatement, expression: Expression, thenStatement: Statement, elseStatement: Statement | undefined): IfStatement;
|
||||
|
||||
createDoStatement(statement: Statement, expression: Expression): DoStatement;
|
||||
updateDoStatement(node: DoStatement, statement: Statement, expression: Expression): DoStatement;
|
||||
|
||||
createWhileStatement(expression: Expression, statement: Statement): WhileStatement;
|
||||
updateWhileStatement(node: WhileStatement, expression: Expression, statement: Statement): WhileStatement;
|
||||
|
||||
createForStatement(initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement;
|
||||
updateForStatement(node: ForStatement, initializer: ForInitializer | undefined, condition: Expression | undefined, incrementor: Expression | undefined, statement: Statement): ForStatement;
|
||||
|
||||
createForInStatement(initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement;
|
||||
updateForInStatement(node: ForInStatement, initializer: ForInitializer, expression: Expression, statement: Statement): ForInStatement;
|
||||
|
||||
createForOfStatement(awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement;
|
||||
updateForOfStatement(node: ForOfStatement, awaitModifier: AwaitKeyword | undefined, initializer: ForInitializer, expression: Expression, statement: Statement): ForOfStatement;
|
||||
|
||||
createContinueStatement(label?: string | Identifier): ContinueStatement;
|
||||
updateContinueStatement(node: ContinueStatement, label: Identifier | undefined): ContinueStatement;
|
||||
|
||||
createBreakStatement(label?: string | Identifier): BreakStatement;
|
||||
updateBreakStatement(node: BreakStatement, label: Identifier | undefined): BreakStatement;
|
||||
|
||||
createReturnStatement(expression?: Expression): ReturnStatement;
|
||||
updateReturnStatement(node: ReturnStatement, expression: Expression | undefined): ReturnStatement;
|
||||
|
||||
createSwitchStatement(expression: Expression, caseBlock: CaseBlock): SwitchStatement;
|
||||
updateSwitchStatement(node: SwitchStatement, expression: Expression, caseBlock: CaseBlock): SwitchStatement;
|
||||
|
||||
createThrowStatement(expression: Expression): ThrowStatement;
|
||||
updateThrowStatement(node: ThrowStatement, expression: Expression): ThrowStatement;
|
||||
|
||||
createTryStatement(tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement;
|
||||
updateTryStatement(node: TryStatement, tryBlock: Block, catchClause: CatchClause | undefined, finallyBlock: Block | undefined): TryStatement;
|
||||
|
||||
/* Declarations */
|
||||
createVariableDeclaration(name: string | BindingName, exclamationToken?: ExclamationToken, type?: TypeNode, initializer?: Expression): VariableDeclaration;
|
||||
updateVariableDeclaration(node: VariableDeclaration, name: BindingName, exclamationToken: ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): VariableDeclaration;
|
||||
|
||||
createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags?: NodeFlags): VariableDeclarationList;
|
||||
updateVariableDeclarationList(node: VariableDeclarationList, declarations: readonly VariableDeclaration[]): VariableDeclarationList;
|
||||
|
||||
createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration;
|
||||
updateFunctionDeclaration(node: FunctionDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration;
|
||||
|
||||
createClassDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration;
|
||||
updateClassDeclaration(node: ClassDeclaration, modifiers: readonly ModifierLike[] | undefined, name: Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly ClassElement[]): ClassDeclaration;
|
||||
|
||||
createPropertyDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration;
|
||||
updatePropertyDeclaration(node: PropertyDeclaration, modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, questionOrExclamationToken: QuestionToken | ExclamationToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertyDeclaration;
|
||||
|
||||
createMethodDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration;
|
||||
updateMethodDeclaration(node: MethodDeclaration, modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): MethodDeclaration;
|
||||
|
||||
createConstructorDeclaration(modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration;
|
||||
updateConstructorDeclaration(node: ConstructorDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], body: Block | undefined): ConstructorDeclaration;
|
||||
|
||||
createInterfaceDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration;
|
||||
updateInterfaceDeclaration(node: InterfaceDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, heritageClauses: readonly HeritageClause[] | undefined, members: readonly TypeElement[]): InterfaceDeclaration;
|
||||
|
||||
createTypeAliasDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration;
|
||||
updateTypeAliasDeclaration(node: TypeAliasDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, typeParameters: readonly TypeParameterDeclaration[] | undefined, type: TypeNode): TypeAliasDeclaration;
|
||||
|
||||
createEnumDeclaration(modifiers: readonly Modifier[] | undefined, name: string | Identifier, members: readonly EnumMember[]): EnumDeclaration;
|
||||
updateEnumDeclaration(node: EnumDeclaration, modifiers: readonly Modifier[] | undefined, name: Identifier, members: readonly EnumMember[]): EnumDeclaration;
|
||||
|
||||
createModuleDeclaration(modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined, flags?: NodeFlags): ModuleDeclaration;
|
||||
updateModuleDeclaration(node: ModuleDeclaration, modifiers: readonly Modifier[] | undefined, name: ModuleName, body: ModuleBody | undefined): ModuleDeclaration;
|
||||
|
||||
createImportEqualsDeclaration(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
|
||||
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
|
||||
|
||||
createImportDeclaration(modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes): ImportDeclaration;
|
||||
updateImportDeclaration(node: ImportDeclaration, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined): ImportDeclaration;
|
||||
|
||||
createExportAssignment(modifiers: readonly Modifier[] | undefined, isExportEquals: boolean | undefined, expression: Expression): ExportAssignment;
|
||||
updateExportAssignment(node: ExportAssignment, modifiers: readonly Modifier[] | undefined, expression: Expression): ExportAssignment;
|
||||
|
||||
createExportDeclaration(modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier?: Expression, attributes?: ImportAttributes): ExportDeclaration;
|
||||
updateExportDeclaration(node: ExportDeclaration, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, exportClause: NamedExportBindings | undefined, moduleSpecifier: Expression | undefined, attributes: ImportAttributes | undefined): ExportDeclaration;
|
||||
|
||||
/* Source File */
|
||||
createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags): SourceFile;
|
||||
updateSourceFile(node: SourceFile, statements: readonly Statement[], isDeclarationFile?: boolean, referencedFiles?: readonly FileReference[], typeReferences?: readonly FileReference[], hasNoDefaultLib?: boolean, libReferences?: readonly FileReference[]): SourceFile;
|
||||
|
||||
/* Type Signatures */
|
||||
createPropertySignature(modifiers: readonly Modifier[] | undefined, name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature;
|
||||
updatePropertySignature(node: PropertySignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined): PropertySignature;
|
||||
createMethodSignature(modifiers: readonly Modifier[] | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): MethodSignature;
|
||||
updateMethodSignature(node: MethodSignature, modifiers: readonly Modifier[] | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): MethodSignature;
|
||||
createCallSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): CallSignatureDeclaration;
|
||||
updateCallSignature(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): CallSignatureDeclaration;
|
||||
createConstructSignature(typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): ConstructSignatureDeclaration;
|
||||
updateConstructSignature(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined): ConstructSignatureDeclaration;
|
||||
createIndexSignature(modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
|
||||
updateIndexSignature(node: IndexSignatureDeclaration, modifiers: readonly ModifierLike[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration;
|
||||
createTemplateLiteralTypeSpan(type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
|
||||
updateTemplateLiteralTypeSpan(node: TemplateLiteralTypeSpan, type: TypeNode, literal: TemplateMiddle | TemplateTail): TemplateLiteralTypeSpan;
|
||||
|
||||
/* Accessors & Class Members */
|
||||
createGetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration;
|
||||
updateGetAccessorDeclaration(node: GetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): GetAccessorDeclaration;
|
||||
createSetAccessorDeclaration(modifiers: readonly ModifierLike[] | undefined, name: string | PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration;
|
||||
updateSetAccessorDeclaration(node: SetAccessorDeclaration, modifiers: readonly ModifierLike[] | undefined, name: PropertyName, parameters: readonly ParameterDeclaration[], body: Block | undefined): SetAccessorDeclaration;
|
||||
createClassStaticBlockDeclaration(body: Block): ClassStaticBlockDeclaration;
|
||||
updateClassStaticBlockDeclaration(node: ClassStaticBlockDeclaration, body: Block): ClassStaticBlockDeclaration;
|
||||
createSemicolonClassElement(): SemicolonClassElement;
|
||||
|
||||
/* Type Nodes */
|
||||
createTypePredicateNode(assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode | string, type: TypeNode | undefined): TypePredicateNode;
|
||||
updateTypePredicateNode(node: TypePredicateNode, assertsModifier: AssertsKeyword | undefined, parameterName: Identifier | ThisTypeNode, type: TypeNode | undefined): TypePredicateNode;
|
||||
createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember;
|
||||
updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember;
|
||||
createOptionalTypeNode(type: TypeNode): OptionalTypeNode;
|
||||
updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode;
|
||||
createRestTypeNode(type: TypeNode): RestTypeNode;
|
||||
updateRestTypeNode(node: RestTypeNode, type: TypeNode): RestTypeNode;
|
||||
createImportTypeNode(argument: TypeNode, attributes?: ImportAttributes, qualifier?: EntityName, typeArguments?: readonly TypeNode[], isTypeOf?: boolean): ImportTypeNode;
|
||||
updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, attributes: ImportAttributes | undefined, qualifier: EntityName | undefined, typeArguments: readonly TypeNode[] | undefined, isTypeOf?: boolean): ImportTypeNode;
|
||||
createParenthesizedType(type: TypeNode): ParenthesizedTypeNode;
|
||||
updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode;
|
||||
createThisTypeNode(): ThisTypeNode;
|
||||
createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode;
|
||||
updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode;
|
||||
createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode;
|
||||
createTemplateLiteralType(head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode;
|
||||
updateTemplateLiteralType(node: TemplateLiteralTypeNode, head: TemplateHead, templateSpans: readonly TemplateLiteralTypeSpan[]): TemplateLiteralTypeNode;
|
||||
|
||||
/* Binding Patterns */
|
||||
createObjectBindingPattern(elements: readonly BindingElement[]): ObjectBindingPattern;
|
||||
updateObjectBindingPattern(node: ObjectBindingPattern, elements: readonly BindingElement[]): ObjectBindingPattern;
|
||||
createArrayBindingPattern(elements: readonly ArrayBindingElement[]): ArrayBindingPattern;
|
||||
updateArrayBindingPattern(node: ArrayBindingPattern, elements: readonly ArrayBindingElement[]): ArrayBindingPattern;
|
||||
createBindingElement(dotDotDotToken: DotDotDotToken | undefined, propertyName: string | PropertyName | undefined, name: string | BindingName, initializer?: Expression): BindingElement;
|
||||
updateBindingElement(node: BindingElement, dotDotDotToken: DotDotDotToken | undefined, propertyName: PropertyName | undefined, name: BindingName, initializer: Expression | undefined): BindingElement;
|
||||
|
||||
/* Statements */
|
||||
createWithStatement(expression: Expression, statement: Statement): WithStatement;
|
||||
updateWithStatement(node: WithStatement, expression: Expression, statement: Statement): WithStatement;
|
||||
createLabeledStatement(label: string | Identifier, statement: Statement): LabeledStatement;
|
||||
updateLabeledStatement(node: LabeledStatement, label: Identifier, statement: Statement): LabeledStatement;
|
||||
createDebuggerStatement(): DebuggerStatement;
|
||||
createNotEmittedStatement(original: Node): NotEmittedStatement;
|
||||
createNotEmittedTypeElement(): NotEmittedTypeElement;
|
||||
|
||||
/* Expressions - Templates */
|
||||
createTemplateExpression(head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression;
|
||||
updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: readonly TemplateSpan[]): TemplateExpression;
|
||||
createTemplateHead(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateHead;
|
||||
createTemplateHead(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateHead;
|
||||
createTemplateMiddle(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateMiddle;
|
||||
createTemplateMiddle(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateMiddle;
|
||||
createTemplateTail(text: string, rawText?: string, templateFlags?: TokenFlags): TemplateTail;
|
||||
createTemplateTail(text: string | undefined, rawText: string, templateFlags?: TokenFlags): TemplateTail;
|
||||
createNoSubstitutionTemplateLiteral(text: string, rawText?: string): NoSubstitutionTemplateLiteral;
|
||||
createNoSubstitutionTemplateLiteral(text: string | undefined, rawText: string): NoSubstitutionTemplateLiteral;
|
||||
createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan;
|
||||
updateTemplateSpan(node: TemplateSpan, expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan;
|
||||
|
||||
/* Expressions - Yield & Other */
|
||||
createYieldExpression(asteriskToken: AsteriskToken, expression: Expression): YieldExpression;
|
||||
createYieldExpression(asteriskToken: undefined, expression: Expression | undefined): YieldExpression;
|
||||
updateYieldExpression(node: YieldExpression, asteriskToken: AsteriskToken | undefined, expression: Expression | undefined): YieldExpression;
|
||||
createOmittedExpression(): OmittedExpression;
|
||||
createExpressionWithTypeArguments(expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments;
|
||||
updateExpressionWithTypeArguments(node: ExpressionWithTypeArguments, expression: Expression, typeArguments: readonly TypeNode[] | undefined): ExpressionWithTypeArguments;
|
||||
createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty;
|
||||
updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty;
|
||||
createPartiallyEmittedExpression(expression: Expression, original?: Node): PartiallyEmittedExpression;
|
||||
updatePartiallyEmittedExpression(node: PartiallyEmittedExpression, expression: Expression): PartiallyEmittedExpression;
|
||||
createCommaListExpression(elements: readonly Expression[]): CommaListExpression;
|
||||
updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]): CommaListExpression;
|
||||
|
||||
/* Expressions - Optional Chaining */
|
||||
createElementAccessChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, index: number | Expression): ElementAccessChain;
|
||||
updateElementAccessChain(node: ElementAccessChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, argumentExpression: Expression): ElementAccessChain;
|
||||
createCallChain(expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[] | undefined): CallChain;
|
||||
updateCallChain(node: CallChain, expression: Expression, questionDotToken: QuestionDotToken | undefined, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]): CallChain;
|
||||
createNonNullChain(expression: Expression): NonNullChain;
|
||||
updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain;
|
||||
|
||||
/* Module & Import/Export */
|
||||
createModuleBlock(statements: readonly Statement[]): ModuleBlock;
|
||||
updateModuleBlock(node: ModuleBlock, statements: readonly Statement[]): ModuleBlock;
|
||||
createCaseBlock(clauses: readonly CaseOrDefaultClause[]): CaseBlock;
|
||||
updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock;
|
||||
createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration;
|
||||
updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
|
||||
createImportAttributes(elements: NodeArray<ImportAttribute>, multiLine?: boolean): ImportAttributes;
|
||||
updateImportAttributes(node: ImportAttributes, elements: NodeArray<ImportAttribute>, multiLine?: boolean): ImportAttributes;
|
||||
createImportAttribute(name: ImportAttributeName, value: Expression): ImportAttribute;
|
||||
updateImportAttribute(node: ImportAttribute, name: ImportAttributeName, value: Expression): ImportAttribute;
|
||||
createNamespaceImport(name: Identifier): NamespaceImport;
|
||||
updateNamespaceImport(node: NamespaceImport, name: Identifier): NamespaceImport;
|
||||
createNamespaceExport(name: ModuleExportName): NamespaceExport;
|
||||
updateNamespaceExport(node: NamespaceExport, name: ModuleExportName): NamespaceExport;
|
||||
createNamedImports(elements: readonly ImportSpecifier[]): NamedImports;
|
||||
updateNamedImports(node: NamedImports, elements: readonly ImportSpecifier[]): NamedImports;
|
||||
createImportSpecifier(isTypeOnly: boolean, propertyName: ModuleExportName | undefined, name: Identifier): ImportSpecifier;
|
||||
updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: ModuleExportName | undefined, name: Identifier): ImportSpecifier;
|
||||
createNamedExports(elements: readonly ExportSpecifier[]): NamedExports;
|
||||
updateNamedExports(node: NamedExports, elements: readonly ExportSpecifier[]): NamedExports;
|
||||
createExportSpecifier(isTypeOnly: boolean, propertyName: string | ModuleExportName | undefined, name: string | ModuleExportName): ExportSpecifier;
|
||||
updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: ModuleExportName | undefined, name: ModuleExportName): ExportSpecifier;
|
||||
createExternalModuleReference(expression: Expression): ExternalModuleReference;
|
||||
updateExternalModuleReference(node: ExternalModuleReference, expression: Expression): ExternalModuleReference;
|
||||
|
||||
/* JSX */
|
||||
createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement;
|
||||
updateJsxElement(node: JsxElement, openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement): JsxElement;
|
||||
createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement;
|
||||
updateJsxSelfClosingElement(node: JsxSelfClosingElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxSelfClosingElement;
|
||||
createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement;
|
||||
updateJsxOpeningElement(node: JsxOpeningElement, tagName: JsxTagNameExpression, typeArguments: readonly TypeNode[] | undefined, attributes: JsxAttributes): JsxOpeningElement;
|
||||
createJsxClosingElement(tagName: JsxTagNameExpression): JsxClosingElement;
|
||||
updateJsxClosingElement(node: JsxClosingElement, tagName: JsxTagNameExpression): JsxClosingElement;
|
||||
createJsxFragment(openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment;
|
||||
updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: readonly JsxChild[], closingFragment: JsxClosingFragment): JsxFragment;
|
||||
createJsxText(text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText;
|
||||
updateJsxText(node: JsxText, text: string, containsOnlyTriviaWhiteSpaces?: boolean): JsxText;
|
||||
createJsxOpeningFragment(): JsxOpeningFragment;
|
||||
createJsxJsxClosingFragment(): JsxClosingFragment;
|
||||
createJsxAttribute(name: JsxAttributeName, initializer: JsxAttributeValue | undefined): JsxAttribute;
|
||||
updateJsxAttribute(node: JsxAttribute, name: JsxAttributeName, initializer: JsxAttributeValue | undefined): JsxAttribute;
|
||||
createJsxAttributes(properties: readonly JsxAttributeLike[]): JsxAttributes;
|
||||
updateJsxAttributes(node: JsxAttributes, properties: readonly JsxAttributeLike[]): JsxAttributes;
|
||||
createJsxSpreadAttribute(expression: Expression): JsxSpreadAttribute;
|
||||
updateJsxSpreadAttribute(node: JsxSpreadAttribute, expression: Expression): JsxSpreadAttribute;
|
||||
createJsxExpression(dotDotDotToken: DotDotDotToken | undefined, expression: Expression | undefined): JsxExpression;
|
||||
updateJsxExpression(node: JsxExpression, expression: Expression | undefined): JsxExpression;
|
||||
createJsxNamespacedName(namespace: Identifier, name: Identifier): JsxNamespacedName;
|
||||
updateJsxNamespacedName(node: JsxNamespacedName, namespace: Identifier, name: Identifier): JsxNamespacedName;
|
||||
|
||||
/* Clauses & Auxiliary Nodes */
|
||||
createCaseClause(expression: Expression, statements: readonly Statement[]): CaseClause;
|
||||
updateCaseClause(node: CaseClause, expression: Expression, statements: readonly Statement[]): CaseClause;
|
||||
createDefaultClause(statements: readonly Statement[]): DefaultClause;
|
||||
updateDefaultClause(node: DefaultClause, statements: readonly Statement[]): DefaultClause;
|
||||
createHeritageClause(token: HeritageClause["token"], types: readonly ExpressionWithTypeArguments[]): HeritageClause;
|
||||
updateHeritageClause(node: HeritageClause, types: readonly ExpressionWithTypeArguments[]): HeritageClause;
|
||||
createCatchClause(variableDeclaration: string | BindingName | VariableDeclaration | undefined, block: Block): CatchClause;
|
||||
updateCatchClause(node: CatchClause, variableDeclaration: VariableDeclaration | undefined, block: Block): CatchClause;
|
||||
createPropertyAssignment(name: string | PropertyName, initializer: Expression): PropertyAssignment;
|
||||
updatePropertyAssignment(node: PropertyAssignment, name: PropertyName, initializer: Expression): PropertyAssignment;
|
||||
createShorthandPropertyAssignment(name: string | Identifier, objectAssignmentInitializer?: Expression): ShorthandPropertyAssignment;
|
||||
updateShorthandPropertyAssignment(node: ShorthandPropertyAssignment, name: Identifier, objectAssignmentInitializer: Expression | undefined): ShorthandPropertyAssignment;
|
||||
createSpreadAssignment(expression: Expression): SpreadAssignment;
|
||||
updateSpreadAssignment(node: SpreadAssignment, expression: Expression): SpreadAssignment;
|
||||
createEnumMember(name: string | PropertyName, initializer?: Expression): EnumMember;
|
||||
updateEnumMember(node: EnumMember, name: PropertyName, initializer: Expression | undefined): EnumMember;
|
||||
|
||||
/* JSDoc Nodes */
|
||||
createJSDocAllType(): JSDocAllType;
|
||||
createJSDocUnknownType(): JSDocUnknownType;
|
||||
createJSDocNonNullableType(type: TypeNode, postfix?: boolean): JSDocNonNullableType;
|
||||
updateJSDocNonNullableType(node: JSDocNonNullableType, type: TypeNode): JSDocNonNullableType;
|
||||
createJSDocNullableType(type: TypeNode, postfix?: boolean): JSDocNullableType;
|
||||
updateJSDocNullableType(node: JSDocNullableType, type: TypeNode): JSDocNullableType;
|
||||
createJSDocOptionalType(type: TypeNode): JSDocOptionalType;
|
||||
updateJSDocOptionalType(node: JSDocOptionalType, type: TypeNode): JSDocOptionalType;
|
||||
createJSDocFunctionType(parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType;
|
||||
updateJSDocFunctionType(node: JSDocFunctionType, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined): JSDocFunctionType;
|
||||
createJSDocVariadicType(type: TypeNode): JSDocVariadicType;
|
||||
updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType;
|
||||
createJSDocNamepathType(type: TypeNode): JSDocNamepathType;
|
||||
updateJSDocNamepathType(node: JSDocNamepathType, type: TypeNode): JSDocNamepathType;
|
||||
createJSDocTypeExpression(type: TypeNode): JSDocTypeExpression;
|
||||
updateJSDocTypeExpression(node: JSDocTypeExpression, type: TypeNode): JSDocTypeExpression;
|
||||
createJSDocNameReference(name: EntityName | JSDocMemberName): JSDocNameReference;
|
||||
updateJSDocNameReference(node: JSDocNameReference, name: EntityName | JSDocMemberName): JSDocNameReference;
|
||||
createJSDocMemberName(left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName;
|
||||
updateJSDocMemberName(node: JSDocMemberName, left: EntityName | JSDocMemberName, right: Identifier): JSDocMemberName;
|
||||
createJSDocLink(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink;
|
||||
updateJSDocLink(node: JSDocLink, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLink;
|
||||
createJSDocLinkCode(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode;
|
||||
updateJSDocLinkCode(node: JSDocLinkCode, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkCode;
|
||||
createJSDocLinkPlain(name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain;
|
||||
updateJSDocLinkPlain(node: JSDocLinkPlain, name: EntityName | JSDocMemberName | undefined, text: string): JSDocLinkPlain;
|
||||
createJSDocTypeLiteral(jsDocPropertyTags?: readonly JSDocPropertyLikeTag[], isArrayType?: boolean): JSDocTypeLiteral;
|
||||
updateJSDocTypeLiteral(node: JSDocTypeLiteral, jsDocPropertyTags: readonly JSDocPropertyLikeTag[] | undefined, isArrayType: boolean | undefined): JSDocTypeLiteral;
|
||||
createJSDocSignature(typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type?: JSDocReturnTag): JSDocSignature;
|
||||
updateJSDocSignature(node: JSDocSignature, typeParameters: readonly JSDocTemplateTag[] | undefined, parameters: readonly JSDocParameterTag[], type: JSDocReturnTag | undefined): JSDocSignature;
|
||||
createJSDocTemplateTag(tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment?: string | NodeArray<JSDocComment>): JSDocTemplateTag;
|
||||
updateJSDocTemplateTag(node: JSDocTemplateTag, tagName: Identifier | undefined, constraint: JSDocTypeExpression | undefined, typeParameters: readonly TypeParameterDeclaration[], comment: string | NodeArray<JSDocComment> | undefined): JSDocTemplateTag;
|
||||
createJSDocTypedefTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression | JSDocTypeLiteral, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocTypedefTag;
|
||||
updateJSDocTypedefTag(node: JSDocTypedefTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | JSDocTypeLiteral | undefined, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocTypedefTag;
|
||||
createJSDocParameterTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray<JSDocComment>): JSDocParameterTag;
|
||||
updateJSDocParameterTag(node: JSDocParameterTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray<JSDocComment> | undefined): JSDocParameterTag;
|
||||
createJSDocPropertyTag(tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, isNameFirst?: boolean, comment?: string | NodeArray<JSDocComment>): JSDocPropertyTag;
|
||||
updateJSDocPropertyTag(node: JSDocPropertyTag, tagName: Identifier | undefined, name: EntityName, isBracketed: boolean, typeExpression: JSDocTypeExpression | undefined, isNameFirst: boolean, comment: string | NodeArray<JSDocComment> | undefined): JSDocPropertyTag;
|
||||
createJSDocTypeTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocTypeTag;
|
||||
updateJSDocTypeTag(node: JSDocTypeTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocTypeTag;
|
||||
createJSDocSeeTag(tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray<JSDocComment>): JSDocSeeTag;
|
||||
updateJSDocSeeTag(node: JSDocSeeTag, tagName: Identifier | undefined, nameExpression: JSDocNameReference | undefined, comment?: string | NodeArray<JSDocComment>): JSDocSeeTag;
|
||||
createJSDocReturnTag(tagName: Identifier | undefined, typeExpression?: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocReturnTag;
|
||||
updateJSDocReturnTag(node: JSDocReturnTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocReturnTag;
|
||||
createJSDocThisTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocThisTag;
|
||||
updateJSDocThisTag(node: JSDocThisTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocThisTag;
|
||||
createJSDocEnumTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocEnumTag;
|
||||
updateJSDocEnumTag(node: JSDocEnumTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocEnumTag;
|
||||
createJSDocCallbackTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName?: Identifier | JSDocNamespaceDeclaration, comment?: string | NodeArray<JSDocComment>): JSDocCallbackTag;
|
||||
updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocCallbackTag;
|
||||
createJSDocOverloadTag(tagName: Identifier | undefined, typeExpression: JSDocSignature, comment?: string | NodeArray<JSDocComment>): JSDocOverloadTag;
|
||||
updateJSDocOverloadTag(node: JSDocOverloadTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, comment: string | NodeArray<JSDocComment> | undefined): JSDocOverloadTag;
|
||||
createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocAugmentsTag;
|
||||
updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocAugmentsTag;
|
||||
createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray<JSDocComment>): JSDocImplementsTag;
|
||||
updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray<JSDocComment> | undefined): JSDocImplementsTag;
|
||||
createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocAuthorTag;
|
||||
updateJSDocAuthorTag(node: JSDocAuthorTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocAuthorTag;
|
||||
createJSDocClassTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocClassTag;
|
||||
updateJSDocClassTag(node: JSDocClassTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocClassTag;
|
||||
createJSDocPublicTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocPublicTag;
|
||||
updateJSDocPublicTag(node: JSDocPublicTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocPublicTag;
|
||||
createJSDocPrivateTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocPrivateTag;
|
||||
updateJSDocPrivateTag(node: JSDocPrivateTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocPrivateTag;
|
||||
createJSDocProtectedTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocProtectedTag;
|
||||
updateJSDocProtectedTag(node: JSDocProtectedTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocProtectedTag;
|
||||
createJSDocReadonlyTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocReadonlyTag;
|
||||
updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocReadonlyTag;
|
||||
createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray<JSDocComment>): JSDocUnknownTag;
|
||||
updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray<JSDocComment> | undefined): JSDocUnknownTag;
|
||||
createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocDeprecatedTag;
|
||||
updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocDeprecatedTag;
|
||||
createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocOverrideTag;
|
||||
updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray<JSDocComment>): JSDocOverrideTag;
|
||||
createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray<JSDocComment>): JSDocThrowsTag;
|
||||
updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray<JSDocComment> | undefined): JSDocThrowsTag;
|
||||
createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray<JSDocComment>): JSDocSatisfiesTag;
|
||||
updateJSDocSatisfiesTag(node: JSDocSatisfiesTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment: string | NodeArray<JSDocComment> | undefined): JSDocSatisfiesTag;
|
||||
createJSDocImportTag(tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes?: ImportAttributes, comment?: string | NodeArray<JSDocComment>): JSDocImportTag;
|
||||
updateJSDocImportTag(node: JSDocImportTag, tagName: Identifier | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression, attributes: ImportAttributes | undefined, comment: string | NodeArray<JSDocComment> | undefined): JSDocImportTag;
|
||||
createJSDocText(text: string): JSDocText;
|
||||
updateJSDocText(node: JSDocText, text: string): JSDocText;
|
||||
createJSDocComment(comment?: string | NodeArray<JSDocComment> | undefined, tags?: readonly JSDocTag[] | undefined): JSDoc;
|
||||
updateJSDocComment(node: JSDoc, comment: string | NodeArray<JSDocComment> | undefined, tags: readonly JSDocTag[] | undefined): JSDoc;
|
||||
|
||||
/* Helper & Convenience Methods */
|
||||
createComma(left: Expression, right: Expression): BinaryExpression;
|
||||
createAssignment(left: Expression, right: Expression): AssignmentExpression<EqualsToken>;
|
||||
createLogicalOr(left: Expression, right: Expression): BinaryExpression;
|
||||
createLogicalAnd(left: Expression, right: Expression): BinaryExpression;
|
||||
createBitwiseOr(left: Expression, right: Expression): BinaryExpression;
|
||||
createBitwiseXor(left: Expression, right: Expression): BinaryExpression;
|
||||
createBitwiseAnd(left: Expression, right: Expression): BinaryExpression;
|
||||
createStrictEquality(left: Expression, right: Expression): BinaryExpression;
|
||||
createStrictInequality(left: Expression, right: Expression): BinaryExpression;
|
||||
createEquality(left: Expression, right: Expression): BinaryExpression;
|
||||
createInequality(left: Expression, right: Expression): BinaryExpression;
|
||||
createLessThan(left: Expression, right: Expression): BinaryExpression;
|
||||
createLessThanEquals(left: Expression, right: Expression): BinaryExpression;
|
||||
createGreaterThan(left: Expression, right: Expression): BinaryExpression;
|
||||
createGreaterThanEquals(left: Expression, right: Expression): BinaryExpression;
|
||||
createLeftShift(left: Expression, right: Expression): BinaryExpression;
|
||||
createRightShift(left: Expression, right: Expression): BinaryExpression;
|
||||
createUnsignedRightShift(left: Expression, right: Expression): BinaryExpression;
|
||||
createAdd(left: Expression, right: Expression): BinaryExpression;
|
||||
createSubtract(left: Expression, right: Expression): BinaryExpression;
|
||||
createMultiply(left: Expression, right: Expression): BinaryExpression;
|
||||
createDivide(left: Expression, right: Expression): BinaryExpression;
|
||||
createModulo(left: Expression, right: Expression): BinaryExpression;
|
||||
createExponent(left: Expression, right: Expression): BinaryExpression;
|
||||
createPrefixPlus(operand: Expression): PrefixUnaryExpression;
|
||||
createPrefixMinus(operand: Expression): PrefixUnaryExpression;
|
||||
createPrefixIncrement(operand: Expression): PrefixUnaryExpression;
|
||||
createPrefixDecrement(operand: Expression): PrefixUnaryExpression;
|
||||
createBitwiseNot(operand: Expression): PrefixUnaryExpression;
|
||||
createLogicalNot(operand: Expression): PrefixUnaryExpression;
|
||||
createPostfixIncrement(operand: Expression): PostfixUnaryExpression;
|
||||
createPostfixDecrement(operand: Expression): PostfixUnaryExpression;
|
||||
createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression;
|
||||
createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression;
|
||||
createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): ImmediatelyInvokedArrowFunction;
|
||||
createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): ImmediatelyInvokedArrowFunction;
|
||||
createVoidZero(): VoidExpression;
|
||||
createExportDefault(expression: Expression): ExportAssignment;
|
||||
createExternalModuleExport(exportName: Identifier): ExportDeclaration;
|
||||
restoreOuterExpressions(outerExpression: Expression | undefined, innerExpression: Expression, kinds?: OuterExpressionKinds): Expression;
|
||||
|
||||
/* Node Replacement Methods */
|
||||
replaceModifiers<T extends HasModifiers>(node: T, modifiers: readonly Modifier[] | ModifierFlags | undefined): T;
|
||||
replaceDecoratorsAndModifiers<T extends HasModifiers & HasDecorators>(node: T, modifiers: readonly ModifierLike[] | undefined): T;
|
||||
replacePropertyName<T extends AccessorDeclaration | MethodDeclaration | MethodSignature | PropertyDeclaration | PropertySignature | PropertyAssignment>(node: T, name: T["name"]): T;
|
||||
|
||||
/* Bundles */
|
||||
createBundle(sourceFiles: readonly SourceFile[]): Bundle;
|
||||
updateBundle(node: Bundle, sourceFiles: readonly SourceFile[]): Bundle;
|
||||
|
||||
/* Node Arrays */
|
||||
createNodeArray<T extends Node>(elements?: readonly T[], hasTrailingComma?: boolean): NodeArray<T>;
|
||||
}
|
||||
```
|
||||
|
||||
### Usage Example
|
||||
|
||||
Creating a simple function declaration:
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const { factory } = ts;
|
||||
|
||||
// Create: function add(a: number, b: number): number { return a + b; }
|
||||
const functionDecl = factory.createFunctionDeclaration(
|
||||
undefined, // modifiers
|
||||
undefined, // asteriskToken
|
||||
'add', // name
|
||||
undefined, // typeParameters
|
||||
[
|
||||
factory.createParameterDeclaration(
|
||||
undefined, // modifiers
|
||||
undefined, // dotDotDotToken
|
||||
'a', // name
|
||||
undefined, // questionToken
|
||||
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) // type
|
||||
),
|
||||
factory.createParameterDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
'b',
|
||||
undefined,
|
||||
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
|
||||
)
|
||||
],
|
||||
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), // return type
|
||||
factory.createBlock([
|
||||
factory.createReturnStatement(
|
||||
factory.createBinaryExpression(
|
||||
factory.createIdentifier('a'),
|
||||
ts.SyntaxKind.PlusToken,
|
||||
factory.createIdentifier('b')
|
||||
)
|
||||
)
|
||||
])
|
||||
);
|
||||
|
||||
// Print the created node
|
||||
const printer = ts.createPrinter();
|
||||
const sourceFile = ts.createSourceFile('temp.ts', '', ts.ScriptTarget.Latest);
|
||||
const output = printer.printNode(ts.EmitHint.Unspecified, functionDecl, sourceFile);
|
||||
console.log(output);
|
||||
```
|
||||
1166
.tessl/tiles/tessl/npm-typescript/docs/ast/nodes.md
Normal file
1166
.tessl/tiles/tessl/npm-typescript/docs/ast/nodes.md
Normal file
File diff suppressed because it is too large
Load diff
327
.tessl/tiles/tessl/npm-typescript/docs/ast/scanner-parser.md
Normal file
327
.tessl/tiles/tessl/npm-typescript/docs/ast/scanner-parser.md
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
# Scanner and Parser
|
||||
|
||||
Low-level lexical analysis and parsing APIs for tokenizing and parsing TypeScript source code.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Scanner Creation
|
||||
|
||||
Create a scanner for lexical analysis.
|
||||
|
||||
```typescript { .api }
|
||||
function createScanner(
|
||||
languageVersion: ScriptTarget,
|
||||
skipTrivia: boolean,
|
||||
languageVariant?: LanguageVariant,
|
||||
textInitial?: string,
|
||||
onError?: ErrorCallback,
|
||||
start?: number,
|
||||
length?: number
|
||||
): Scanner;
|
||||
|
||||
type ErrorCallback = (message: DiagnosticMessage, length: number, arg0?: any) => void;
|
||||
```
|
||||
|
||||
### Scanner Interface
|
||||
|
||||
```typescript { .api }
|
||||
interface Scanner {
|
||||
/** @deprecated use getTokenFullStart */
|
||||
getStartPos(): number;
|
||||
getToken(): SyntaxKind;
|
||||
getTokenFullStart(): number;
|
||||
getTokenStart(): number;
|
||||
getTokenEnd(): number;
|
||||
/** @deprecated use getTokenEnd */
|
||||
getTextPos(): number;
|
||||
/** @deprecated use getTokenStart */
|
||||
getTokenPos(): number;
|
||||
getTokenText(): string;
|
||||
getTokenValue(): string;
|
||||
hasUnicodeEscape(): boolean;
|
||||
hasExtendedUnicodeEscape(): boolean;
|
||||
hasPrecedingLineBreak(): boolean;
|
||||
isIdentifier(): boolean;
|
||||
isReservedWord(): boolean;
|
||||
isUnterminated(): boolean;
|
||||
reScanGreaterToken(): SyntaxKind;
|
||||
reScanSlashToken(): SyntaxKind;
|
||||
reScanAsteriskEqualsToken(): SyntaxKind;
|
||||
reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind;
|
||||
/** @deprecated use reScanTemplateToken(false) */
|
||||
reScanTemplateHeadOrNoSubstitutionTemplate(): SyntaxKind;
|
||||
scanJsxIdentifier(): SyntaxKind;
|
||||
scanJsxAttributeValue(): SyntaxKind;
|
||||
reScanJsxAttributeValue(): SyntaxKind;
|
||||
reScanJsxToken(allowMultilineJsxText?: boolean): JsxTokenSyntaxKind;
|
||||
reScanLessThanToken(): SyntaxKind;
|
||||
reScanHashToken(): SyntaxKind;
|
||||
reScanQuestionToken(): SyntaxKind;
|
||||
reScanInvalidIdentifier(): SyntaxKind;
|
||||
scanJsxToken(): JsxTokenSyntaxKind;
|
||||
scanJsDocToken(): JSDocSyntaxKind;
|
||||
scan(): SyntaxKind;
|
||||
getText(): string;
|
||||
setText(text: string | undefined, start?: number, length?: number): void;
|
||||
setOnError(onError: ErrorCallback | undefined): void;
|
||||
setScriptTarget(scriptTarget: ScriptTarget): void;
|
||||
setLanguageVariant(variant: LanguageVariant): void;
|
||||
setScriptKind(scriptKind: ScriptKind): void;
|
||||
setJSDocParsingMode(kind: JSDocParsingMode): void;
|
||||
/** @deprecated use resetTokenState */
|
||||
setTextPos(textPos: number): void;
|
||||
resetTokenState(pos: number): void;
|
||||
lookAhead<T>(callback: () => T): T;
|
||||
scanRange<T>(start: number, length: number, callback: () => T): T;
|
||||
tryScan<T>(callback: () => T): T;
|
||||
}
|
||||
```
|
||||
|
||||
### Source File Creation
|
||||
|
||||
Parse source code into an AST.
|
||||
|
||||
```typescript { .api }
|
||||
function createSourceFile(
|
||||
fileName: string,
|
||||
sourceText: string,
|
||||
languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions,
|
||||
setParentNodes?: boolean,
|
||||
scriptKind?: ScriptKind
|
||||
): SourceFile;
|
||||
|
||||
interface CreateSourceFileOptions {
|
||||
languageVersion: ScriptTarget;
|
||||
impliedNodeFormat?: ResolutionMode;
|
||||
setExternalModuleIndicator?: (file: SourceFile) => void;
|
||||
jsDocParsingMode?: JSDocParsingMode;
|
||||
}
|
||||
```
|
||||
|
||||
### Source File Interface
|
||||
|
||||
```typescript { .api }
|
||||
interface SourceFile extends Declaration {
|
||||
readonly kind: SyntaxKind.SourceFile;
|
||||
readonly statements: NodeArray<Statement>;
|
||||
readonly endOfFileToken: Token<SyntaxKind.EndOfFileToken>;
|
||||
readonly fileName: string;
|
||||
readonly text: string;
|
||||
readonly amdDependencies: readonly AmdDependency[];
|
||||
readonly moduleName?: string;
|
||||
readonly referencedFiles: readonly FileReference[];
|
||||
readonly typeReferenceDirectives: readonly FileReference[];
|
||||
readonly libReferenceDirectives: readonly FileReference[];
|
||||
readonly languageVariant: LanguageVariant;
|
||||
readonly isDeclarationFile: boolean;
|
||||
readonly hasNoDefaultLib: boolean;
|
||||
readonly languageVersion: ScriptTarget;
|
||||
readonly scriptKind: ScriptKind;
|
||||
readonly externalModuleIndicator?: Node;
|
||||
readonly commonJsModuleIndicator?: Node;
|
||||
readonly identifiers: Map<string, string>;
|
||||
readonly nodeCount: number;
|
||||
readonly identifierCount: number;
|
||||
readonly symbolCount: number;
|
||||
readonly parseDiagnostics: DiagnosticWithLocation[];
|
||||
readonly bindDiagnostics: readonly Diagnostic[];
|
||||
readonly bindSuggestionDiagnostics?: readonly Diagnostic[];
|
||||
readonly jsDocDiagnostics?: readonly Diagnostic[];
|
||||
readonly additionalSyntacticDiagnostics?: readonly DiagnosticWithLocation[];
|
||||
readonly lineMap: readonly number[];
|
||||
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
getLineEndOfPosition(pos: number): number;
|
||||
getLineStarts(): readonly number[];
|
||||
getPositionOfLineAndCharacter(line: number, character: number): number;
|
||||
update(newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
}
|
||||
|
||||
interface SourceFileLike {
|
||||
readonly text: string;
|
||||
readonly lineMap?: readonly number[];
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
}
|
||||
```
|
||||
|
||||
### Language Variant
|
||||
|
||||
```typescript { .api }
|
||||
enum LanguageVariant {
|
||||
Standard = 0,
|
||||
JSX = 1
|
||||
}
|
||||
|
||||
enum ScriptKind {
|
||||
Unknown = 0,
|
||||
JS = 1,
|
||||
JSX = 2,
|
||||
TS = 3,
|
||||
TSX = 4,
|
||||
External = 5,
|
||||
JSON = 6,
|
||||
Deferred = 7
|
||||
}
|
||||
```
|
||||
|
||||
### JSDoc Parsing
|
||||
|
||||
```typescript { .api }
|
||||
enum JSDocParsingMode {
|
||||
ParseAll = 0,
|
||||
ParseNone = 1,
|
||||
ParseForTypeErrors = 2,
|
||||
ParseForTypeInfo = 3
|
||||
}
|
||||
|
||||
function parseIsolatedEntityName(text: string, languageVersion: ScriptTarget): EntityName | undefined;
|
||||
function parseJsonText(fileName: string, sourceText: string): JsonSourceFile;
|
||||
```
|
||||
|
||||
### Pre-Processed File Info
|
||||
|
||||
Get file dependencies without full parsing.
|
||||
|
||||
```typescript { .api }
|
||||
function preProcessFile(
|
||||
sourceText: string,
|
||||
readImportFiles?: boolean,
|
||||
detectJavaScriptImports?: boolean
|
||||
): PreProcessedFileInfo;
|
||||
|
||||
interface PreProcessedFileInfo {
|
||||
referencedFiles: FileReference[];
|
||||
typeReferenceDirectives: FileReference[];
|
||||
libReferenceDirectives: FileReference[];
|
||||
importedFiles: FileReference[];
|
||||
ambientExternalModules?: string[];
|
||||
isLibFile: boolean;
|
||||
}
|
||||
|
||||
interface FileReference extends TextRange {
|
||||
fileName: string;
|
||||
resolutionMode?: ResolutionMode;
|
||||
}
|
||||
```
|
||||
|
||||
### Text Range
|
||||
|
||||
```typescript { .api }
|
||||
interface TextRange {
|
||||
pos: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
interface ReadonlyTextRange {
|
||||
readonly pos: number;
|
||||
readonly end: number;
|
||||
}
|
||||
|
||||
interface TextSpan {
|
||||
start: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface TextChangeRange {
|
||||
span: TextSpan;
|
||||
newLength: number;
|
||||
}
|
||||
|
||||
function createTextSpan(start: number, length: number): TextSpan;
|
||||
function createTextSpanFromBounds(start: number, end: number): TextSpan;
|
||||
function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange;
|
||||
function collapseTextChangeRangesAcrossMultipleVersions(changes: readonly TextChangeRange[]): TextChangeRange;
|
||||
```
|
||||
|
||||
### Comment Ranges
|
||||
|
||||
```typescript { .api }
|
||||
function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined;
|
||||
function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined;
|
||||
function getShebang(text: string): string | undefined;
|
||||
function isIdentifierStart(ch: number, languageVersion: ScriptTarget | undefined): boolean;
|
||||
function isIdentifierPart(ch: number, languageVersion: ScriptTarget | undefined, identifierVariant?: LanguageVariant): boolean;
|
||||
|
||||
interface CommentRange extends TextRange {
|
||||
kind: CommentKind;
|
||||
hasTrailingNewLine?: boolean;
|
||||
}
|
||||
|
||||
enum CommentKind {
|
||||
SingleLine = 2,
|
||||
MultiLine = 3
|
||||
}
|
||||
```
|
||||
|
||||
### Token Utilities
|
||||
|
||||
```typescript { .api }
|
||||
function isKeyword(kind: SyntaxKind): boolean;
|
||||
function isModifier(kind: SyntaxKind): boolean;
|
||||
function isFutureReservedKeyword(kind: SyntaxKind): boolean;
|
||||
function isContextualKeyword(kind: SyntaxKind): boolean;
|
||||
function isStringANonContextualKeyword(name: string): boolean;
|
||||
function isStringAKeyword(name: string): boolean;
|
||||
function isIdentifierANonContextualKeyword(node: Identifier): boolean;
|
||||
function isTrivia(kind: SyntaxKind): boolean;
|
||||
function isPunctuation(kind: SyntaxKind): boolean;
|
||||
function couldStartTrivia(text: string, pos: number): boolean;
|
||||
function scanString(text: string, start: number, astral?: boolean): string | undefined;
|
||||
function getTokenText(kind: SyntaxKind): string | undefined;
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
Using the scanner to tokenize source code:
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const code = 'const x: number = 42;';
|
||||
const scanner = ts.createScanner(
|
||||
ts.ScriptTarget.Latest,
|
||||
false, // don't skip trivia
|
||||
ts.LanguageVariant.Standard,
|
||||
code
|
||||
);
|
||||
|
||||
let token: ts.SyntaxKind;
|
||||
while ((token = scanner.scan()) !== ts.SyntaxKind.EndOfFileToken) {
|
||||
const start = scanner.getTokenStart();
|
||||
const end = scanner.getTokenEnd();
|
||||
const text = scanner.getTokenText();
|
||||
|
||||
console.log(
|
||||
ts.SyntaxKind[token],
|
||||
`"${text}"`,
|
||||
`(${start}-${end})`
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Parsing source code:
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const code = `
|
||||
function greet(name: string): string {
|
||||
return 'Hello, ' + name;
|
||||
}
|
||||
`;
|
||||
|
||||
const sourceFile = ts.createSourceFile(
|
||||
'example.ts',
|
||||
code,
|
||||
ts.ScriptTarget.Latest,
|
||||
true // set parent nodes
|
||||
);
|
||||
|
||||
console.log('File name:', sourceFile.fileName);
|
||||
console.log('Statements:', sourceFile.statements.length);
|
||||
console.log('Parse diagnostics:', sourceFile.parseDiagnostics.length);
|
||||
|
||||
// Print line and character for position 0
|
||||
const lineChar = sourceFile.getLineAndCharacterOfPosition(0);
|
||||
console.log(`Position 0 is at line ${lineChar.line}, character ${lineChar.character}`);
|
||||
```
|
||||
133
.tessl/tiles/tessl/npm-typescript/docs/ast/type-guards.md
Normal file
133
.tessl/tiles/tessl/npm-typescript/docs/ast/type-guards.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# Type Guards
|
||||
|
||||
Comprehensive type guard functions for all AST node types.
|
||||
|
||||
## Type Guard Functions
|
||||
|
||||
```typescript { .api }
|
||||
function isSourceFile(node: Node): node is SourceFile;
|
||||
function isIdentifier(node: Node): node is Identifier;
|
||||
function isQualifiedName(node: Node): node is QualifiedName;
|
||||
function isComputedPropertyName(node: Node): node is ComputedPropertyName;
|
||||
function isPrivateIdentifier(node: Node): node is PrivateIdentifier;
|
||||
function isTypeParameterDeclaration(node: Node): node is TypeParameterDeclaration;
|
||||
function isParameter(node: Node): node is ParameterDeclaration;
|
||||
function isDecorator(node: Node): node is Decorator;
|
||||
function isPropertySignature(node: Node): node is PropertySignature;
|
||||
function isPropertyDeclaration(node: Node): node is PropertyDeclaration;
|
||||
function isMethodSignature(node: Node): node is MethodSignature;
|
||||
function isMethodDeclaration(node: Node): node is MethodDeclaration;
|
||||
function isClassStaticBlockDeclaration(node: Node): node is ClassStaticBlockDeclaration;
|
||||
function isConstructorDeclaration(node: Node): node is ConstructorDeclaration;
|
||||
function isGetAccessorDeclaration(node: Node): node is GetAccessorDeclaration;
|
||||
function isSetAccessorDeclaration(node: Node): node is SetAccessorDeclaration;
|
||||
function isCallSignatureDeclaration(node: Node): node is CallSignatureDeclaration;
|
||||
function isConstructSignatureDeclaration(node: Node): node is ConstructSignatureDeclaration;
|
||||
function isIndexSignatureDeclaration(node: Node): node is IndexSignatureDeclaration;
|
||||
function isTypePredicateNode(node: Node): node is TypePredicateNode;
|
||||
function isTypeReferenceNode(node: Node): node is TypeReferenceNode;
|
||||
function isFunctionTypeNode(node: Node): node is FunctionTypeNode;
|
||||
function isConstructorTypeNode(node: Node): node is ConstructorTypeNode;
|
||||
function isTypeQueryNode(node: Node): node is TypeQueryNode;
|
||||
function isTypeLiteralNode(node: Node): node is TypeLiteralNode;
|
||||
function isArrayTypeNode(node: Node): node is ArrayTypeNode;
|
||||
function isTupleTypeNode(node: Node): node is TupleTypeNode;
|
||||
function isUnionTypeNode(node: Node): node is UnionTypeNode;
|
||||
function isIntersectionTypeNode(node: Node): node is IntersectionTypeNode;
|
||||
function isConditionalTypeNode(node: Node): node is ConditionalTypeNode;
|
||||
function isInferTypeNode(node: Node): node is InferTypeNode;
|
||||
function isParenthesizedTypeNode(node: Node): node is ParenthesizedTypeNode;
|
||||
function isThisTypeNode(node: Node): node is ThisTypeNode;
|
||||
function isTypeOperatorNode(node: Node): node is TypeOperatorNode;
|
||||
function isIndexedAccessTypeNode(node: Node): node is IndexedAccessTypeNode;
|
||||
function isMappedTypeNode(node: Node): node is MappedTypeNode;
|
||||
function isLiteralTypeNode(node: Node): node is LiteralTypeNode;
|
||||
function isBooleanLiteral(node: Node): node is BooleanLiteral;
|
||||
function isFunctionExpression(node: Node): node is FunctionExpression;
|
||||
function isArrowFunction(node: Node): node is ArrowFunction;
|
||||
function isArrayLiteralExpression(node: Node): node is ArrayLiteralExpression;
|
||||
function isObjectLiteralExpression(node: Node): node is ObjectLiteralExpression;
|
||||
function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression;
|
||||
function isElementAccessExpression(node: Node): node is ElementAccessExpression;
|
||||
function isCallExpression(node: Node): node is CallExpression;
|
||||
function isNewExpression(node: Node): node is NewExpression;
|
||||
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
|
||||
function isTypeAssertionExpression(node: Node): node is TypeAssertion;
|
||||
function isParenthesizedExpression(node: Node): node is ParenthesizedExpression;
|
||||
function isDeleteExpression(node: Node): node is DeleteExpression;
|
||||
function isTypeOfExpression(node: Node): node is TypeOfExpression;
|
||||
function isVoidExpression(node: Node): node is VoidExpression;
|
||||
function isAwaitExpression(node: Node): node is AwaitExpression;
|
||||
function isPrefixUnaryExpression(node: Node): node is PrefixUnaryExpression;
|
||||
function isPostfixUnaryExpression(node: Node): node is PostfixUnaryExpression;
|
||||
function isBinaryExpression(node: Node): node is BinaryExpression;
|
||||
function isConditionalExpression(node: Node): node is ConditionalExpression;
|
||||
function isTemplateExpression(node: Node): node is TemplateExpression;
|
||||
function isYieldExpression(node: Node): node is YieldExpression;
|
||||
function isSpreadElement(node: Node): node is SpreadElement;
|
||||
function isClassExpression(node: Node): node is ClassExpression;
|
||||
function isOmittedExpression(node: Node): node is OmittedExpression;
|
||||
function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments;
|
||||
function isAsExpression(node: Node): node is AsExpression;
|
||||
function isNonNullExpression(node: Node): node is NonNullExpression;
|
||||
function isSatisfiesExpression(node: Node): node is SatisfiesExpression;
|
||||
function isBlock(node: Node): node is Block;
|
||||
function isVariableStatement(node: Node): node is VariableStatement;
|
||||
function isEmptyStatement(node: Node): node is EmptyStatement;
|
||||
function isExpressionStatement(node: Node): node is ExpressionStatement;
|
||||
function isIfStatement(node: Node): node is IfStatement;
|
||||
function isDoStatement(node: Node): node is DoStatement;
|
||||
function isWhileStatement(node: Node): node is WhileStatement;
|
||||
function isForStatement(node: Node): node is ForStatement;
|
||||
function isForInStatement(node: Node): node is ForInStatement;
|
||||
function isForOfStatement(node: Node): node is ForOfStatement;
|
||||
function isContinueStatement(node: Node): node is ContinueStatement;
|
||||
function isBreakStatement(node: Node): node is BreakStatement;
|
||||
function isReturnStatement(node: Node): node is ReturnStatement;
|
||||
function isWithStatement(node: Node): node is WithStatement;
|
||||
function isSwitchStatement(node: Node): node is SwitchStatement;
|
||||
function isLabeledStatement(node: Node): node is LabeledStatement;
|
||||
function isThrowStatement(node: Node): node is ThrowStatement;
|
||||
function isTryStatement(node: Node): node is TryStatement;
|
||||
function isDebuggerStatement(node: Node): node is DebuggerStatement;
|
||||
function isVariableDeclaration(node: Node): node is VariableDeclaration;
|
||||
function isVariableDeclarationList(node: Node): node is VariableDeclarationList;
|
||||
function isFunctionDeclaration(node: Node): node is FunctionDeclaration;
|
||||
function isClassDeclaration(node: Node): node is ClassDeclaration;
|
||||
function isInterfaceDeclaration(node: Node): node is InterfaceDeclaration;
|
||||
function isTypeAliasDeclaration(node: Node): node is TypeAliasDeclaration;
|
||||
function isEnumDeclaration(node: Node): node is EnumDeclaration;
|
||||
function isModuleDeclaration(node: Node): node is ModuleDeclaration;
|
||||
function isImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration;
|
||||
function isImportDeclaration(node: Node): node is ImportDeclaration;
|
||||
function isExportAssignment(node: Node): node is ExportAssignment;
|
||||
function isExportDeclaration(node: Node): node is ExportDeclaration;
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
function visit(node: ts.Node) {
|
||||
if (ts.isFunctionDeclaration(node)) {
|
||||
console.log('Found function:', node.name?.getText());
|
||||
} else if (ts.isVariableDeclaration(node)) {
|
||||
console.log('Found variable:', node.name.getText());
|
||||
} else if (ts.isCallExpression(node)) {
|
||||
console.log('Found call expression');
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
const sourceFile = ts.createSourceFile(
|
||||
'example.ts',
|
||||
'function foo() { const x = 1; }',
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
visit(sourceFile);
|
||||
```
|
||||
|
||||
589
.tessl/tiles/tessl/npm-typescript/docs/core/compilation.md
Normal file
589
.tessl/tiles/tessl/npm-typescript/docs/core/compilation.md
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
# Core Compilation APIs
|
||||
|
||||
Core TypeScript compiler APIs for program creation, compilation, and code generation.
|
||||
|
||||
## Program Creation
|
||||
|
||||
Create and manage TypeScript programs.
|
||||
|
||||
```typescript { .api }
|
||||
function createProgram(
|
||||
rootNames: readonly string[],
|
||||
options: CompilerOptions,
|
||||
host?: CompilerHost,
|
||||
oldProgram?: Program,
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[]
|
||||
): Program;
|
||||
|
||||
function createProgram(createProgramOptions: CreateProgramOptions): Program;
|
||||
|
||||
interface CreateProgramOptions {
|
||||
rootNames: readonly string[];
|
||||
options: CompilerOptions;
|
||||
projectReferences?: readonly ProjectReference[];
|
||||
host?: CompilerHost;
|
||||
oldProgram?: Program;
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[];
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const options: ts.CompilerOptions = {
|
||||
target: ts.ScriptTarget.ES2020,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
strict: true,
|
||||
esModuleInterop: true
|
||||
};
|
||||
|
||||
const program = ts.createProgram({
|
||||
rootNames: ['index.ts', 'utils.ts'],
|
||||
options
|
||||
});
|
||||
```
|
||||
|
||||
## Program Interface
|
||||
|
||||
Main program interface for compilation operations.
|
||||
|
||||
```typescript { .api }
|
||||
interface Program {
|
||||
getRootFileNames(): readonly string[];
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
getTypeChecker(): TypeChecker;
|
||||
getNodeCount(): number;
|
||||
getIdentifierCount(): number;
|
||||
getSymbolCount(): number;
|
||||
getTypeCount(): number;
|
||||
getInstantiationCount(): number;
|
||||
getRelationCacheSizes(): {
|
||||
assignable: number;
|
||||
identity: number;
|
||||
subtype: number;
|
||||
strictSubtype: number;
|
||||
};
|
||||
emit(
|
||||
targetSourceFile?: SourceFile,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
): EmitResult;
|
||||
getSemanticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly Diagnostic[];
|
||||
getSyntacticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly DiagnosticWithLocation[];
|
||||
getDeclarationDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly DiagnosticWithLocation[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getCurrentDirectory(): string;
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getProjectReferences(): readonly ProjectReference[] | undefined;
|
||||
getResolvedProjectReferences(): readonly (ResolvedProjectReference | undefined)[] | undefined;
|
||||
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
|
||||
isSourceFileDefaultLibrary(file: SourceFile): boolean;
|
||||
getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
}
|
||||
```
|
||||
|
||||
## Compiler Options
|
||||
|
||||
Comprehensive compiler configuration options.
|
||||
|
||||
```typescript { .api }
|
||||
interface CompilerOptions {
|
||||
/* Language and Environment */
|
||||
target?: ScriptTarget;
|
||||
lib?: string[];
|
||||
jsx?: JsxEmit;
|
||||
experimentalDecorators?: boolean;
|
||||
emitDecoratorMetadata?: boolean;
|
||||
jsxFactory?: string;
|
||||
jsxFragmentFactory?: string;
|
||||
jsxImportSource?: string;
|
||||
reactNamespace?: string;
|
||||
noLib?: boolean;
|
||||
useDefineForClassFields?: boolean;
|
||||
moduleDetection?: ModuleDetectionKind;
|
||||
|
||||
/* Modules */
|
||||
module?: ModuleKind;
|
||||
moduleResolution?: ModuleResolutionKind;
|
||||
moduleSuffixes?: string[];
|
||||
noResolve?: boolean;
|
||||
paths?: MapLike<string[]>;
|
||||
rootDirs?: string[];
|
||||
rootDir?: string;
|
||||
typeRoots?: string[];
|
||||
types?: string[];
|
||||
allowArbitraryExtensions?: boolean;
|
||||
allowImportingTsExtensions?: boolean;
|
||||
allowUmdGlobalAccess?: boolean;
|
||||
baseUrl?: string;
|
||||
customConditions?: string[];
|
||||
resolveJsonModule?: boolean;
|
||||
resolvePackageJsonExports?: boolean;
|
||||
resolvePackageJsonImports?: boolean;
|
||||
rewriteRelativeImportExtensions?: boolean;
|
||||
noUncheckedSideEffectImports?: boolean;
|
||||
|
||||
/* JavaScript Support */
|
||||
allowJs?: boolean;
|
||||
checkJs?: boolean;
|
||||
maxNodeModuleJsDepth?: number;
|
||||
|
||||
/* Emit */
|
||||
declaration?: boolean;
|
||||
declarationMap?: boolean;
|
||||
declarationDir?: string;
|
||||
emitDeclarationOnly?: boolean;
|
||||
downlevelIteration?: boolean;
|
||||
emitBOM?: boolean;
|
||||
importHelpers?: boolean;
|
||||
inlineSourceMap?: boolean;
|
||||
inlineSources?: boolean;
|
||||
mapRoot?: string;
|
||||
newLine?: NewLineKind;
|
||||
noEmit?: boolean;
|
||||
noEmitHelpers?: boolean;
|
||||
noEmitOnError?: boolean;
|
||||
outDir?: string;
|
||||
outFile?: string;
|
||||
preserveConstEnums?: boolean;
|
||||
preserveValueImports?: boolean;
|
||||
removeComments?: boolean;
|
||||
sourceMap?: boolean;
|
||||
sourceRoot?: string;
|
||||
stripInternal?: boolean;
|
||||
|
||||
/* Interop Constraints */
|
||||
allowSyntheticDefaultImports?: boolean;
|
||||
esModuleInterop?: boolean;
|
||||
forceConsistentCasingInFileNames?: boolean;
|
||||
isolatedModules?: boolean;
|
||||
isolatedDeclarations?: boolean;
|
||||
preserveSymlinks?: boolean;
|
||||
verbatimModuleSyntax?: boolean;
|
||||
|
||||
/* Type Checking */
|
||||
strict?: boolean;
|
||||
alwaysStrict?: boolean;
|
||||
exactOptionalPropertyTypes?: boolean;
|
||||
noFallthroughCasesInSwitch?: boolean;
|
||||
noImplicitAny?: boolean;
|
||||
noImplicitOverride?: boolean;
|
||||
noImplicitReturns?: boolean;
|
||||
noImplicitThis?: boolean;
|
||||
noPropertyAccessFromIndexSignature?: boolean;
|
||||
noUncheckedIndexedAccess?: boolean;
|
||||
noUnusedLocals?: boolean;
|
||||
noUnusedParameters?: boolean;
|
||||
strictBindCallApply?: boolean;
|
||||
strictBuiltinIteratorReturn?: boolean;
|
||||
strictFunctionTypes?: boolean;
|
||||
strictNullChecks?: boolean;
|
||||
strictPropertyInitialization?: boolean;
|
||||
useUnknownInCatchVariables?: boolean;
|
||||
|
||||
/* Completeness */
|
||||
skipDefaultLibCheck?: boolean;
|
||||
skipLibCheck?: boolean;
|
||||
|
||||
/* Project References */
|
||||
composite?: boolean;
|
||||
disableReferencedProjectLoad?: boolean;
|
||||
disableSolutionSearching?: boolean;
|
||||
disableSourceOfProjectReferenceRedirect?: boolean;
|
||||
incremental?: boolean;
|
||||
tsBuildInfoFile?: string;
|
||||
|
||||
/* Advanced */
|
||||
allowUnreachableCode?: boolean;
|
||||
allowUnusedLabels?: boolean;
|
||||
assumeChangesOnlyAffectDirectDependencies?: boolean;
|
||||
disableSizeLimit?: boolean;
|
||||
noCheck?: boolean;
|
||||
noErrorTruncation?: boolean;
|
||||
preserveWatchOutput?: boolean;
|
||||
suppressExcessPropertyErrors?: boolean;
|
||||
suppressImplicitAnyIndexErrors?: boolean;
|
||||
traceResolution?: boolean;
|
||||
ignoreDeprecations?: string;
|
||||
|
||||
[option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined;
|
||||
}
|
||||
|
||||
type CompilerOptionsValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| (string | number)[]
|
||||
| string[]
|
||||
| MapLike<string[]>
|
||||
| PluginImport[]
|
||||
| ProjectReference[]
|
||||
| null
|
||||
| undefined;
|
||||
```
|
||||
|
||||
## Compiler Host
|
||||
|
||||
Interface for file system operations during compilation.
|
||||
|
||||
```typescript { .api }
|
||||
interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(
|
||||
fileName: string,
|
||||
languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions,
|
||||
onError?: (message: string) => void,
|
||||
shouldCreateNewSourceFile?: boolean
|
||||
): SourceFile | undefined;
|
||||
|
||||
getSourceFileByPath?(
|
||||
fileName: string,
|
||||
path: Path,
|
||||
languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions,
|
||||
onError?: (message: string) => void,
|
||||
shouldCreateNewSourceFile?: boolean
|
||||
): SourceFile | undefined;
|
||||
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
writeFile: WriteFileCallback;
|
||||
getCurrentDirectory(): string;
|
||||
getCanonicalFileName(fileName: string): string;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
readDirectory?(
|
||||
rootDir: string,
|
||||
extensions: readonly string[],
|
||||
excludes: readonly string[] | undefined,
|
||||
includes: readonly string[],
|
||||
depth?: number
|
||||
): string[];
|
||||
resolveModuleNameLiterals?(
|
||||
moduleLiterals: readonly StringLiteralLike[],
|
||||
containingFile: string,
|
||||
redirectedReference: ResolvedProjectReference | undefined,
|
||||
options: CompilerOptions,
|
||||
containingSourceFile: SourceFile,
|
||||
reusedNames: readonly StringLiteralLike[] | undefined
|
||||
): readonly ResolvedModuleWithFailedLookupLocations[];
|
||||
resolveTypeReferenceDirectiveReferences?<T extends FileReference | string>(
|
||||
typeDirectiveReferences: readonly T[],
|
||||
containingFile: string,
|
||||
redirectedReference: ResolvedProjectReference | undefined,
|
||||
options: CompilerOptions,
|
||||
containingSourceFile: SourceFile | undefined,
|
||||
reusedNames: readonly T[] | undefined
|
||||
): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[];
|
||||
getEnvironmentVariable?(name: string): string | undefined;
|
||||
hasInvalidatedResolutions?(filePath: Path): boolean;
|
||||
createHash?(data: string): string;
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
jsDocParsingMode?: JSDocParsingMode;
|
||||
}
|
||||
|
||||
type WriteFileCallback = (
|
||||
fileName: string,
|
||||
text: string,
|
||||
writeByteOrderMark: boolean,
|
||||
onError?: (message: string) => void,
|
||||
sourceFiles?: readonly SourceFile[],
|
||||
data?: WriteFileCallbackData
|
||||
) => void;
|
||||
|
||||
function createCompilerHost(
|
||||
options: CompilerOptions,
|
||||
setParentNodes?: boolean
|
||||
): CompilerHost;
|
||||
```
|
||||
|
||||
## Emit Result
|
||||
|
||||
Result of program emit operation.
|
||||
|
||||
```typescript { .api }
|
||||
interface EmitResult {
|
||||
emitSkipped: boolean;
|
||||
diagnostics: readonly Diagnostic[];
|
||||
emittedFiles?: string[];
|
||||
}
|
||||
|
||||
interface EmitOutput {
|
||||
outputFiles: OutputFile[];
|
||||
emitSkipped: boolean;
|
||||
}
|
||||
|
||||
interface OutputFile {
|
||||
name: string;
|
||||
writeByteOrderMark: boolean;
|
||||
text: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Incremental Compilation
|
||||
|
||||
Incremental compilation APIs enable faster rebuilds by reusing previous compilation state.
|
||||
|
||||
```typescript { .api }
|
||||
function createIncrementalCompilerHost(
|
||||
options: CompilerOptions,
|
||||
system?: System
|
||||
): CompilerHost;
|
||||
|
||||
function createIncrementalProgram<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(
|
||||
options: IncrementalProgramOptions<T>
|
||||
): T;
|
||||
|
||||
interface IncrementalProgramOptions<T extends BuilderProgram> {
|
||||
rootNames: readonly string[];
|
||||
options: CompilerOptions;
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[];
|
||||
projectReferences?: readonly ProjectReference[];
|
||||
host?: CompilerHost;
|
||||
createProgram?: CreateProgram<T>;
|
||||
}
|
||||
|
||||
function readBuilderProgram(
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ReadBuildProgramHost
|
||||
): EmitAndSemanticDiagnosticsBuilderProgram | undefined;
|
||||
|
||||
interface ReadBuildProgramHost {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
readFile(fileName: string): string | undefined;
|
||||
}
|
||||
|
||||
function createEmitAndSemanticDiagnosticsBuilderProgram(
|
||||
rootNames: readonly string[] | undefined,
|
||||
options: CompilerOptions | undefined,
|
||||
host?: CompilerHost,
|
||||
oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram,
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[],
|
||||
projectReferences?: readonly ProjectReference[]
|
||||
): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
|
||||
function createSemanticDiagnosticsBuilderProgram(
|
||||
rootNames: readonly string[] | undefined,
|
||||
options: CompilerOptions | undefined,
|
||||
host?: CompilerHost,
|
||||
oldProgram?: SemanticDiagnosticsBuilderProgram,
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[],
|
||||
projectReferences?: readonly ProjectReference[]
|
||||
): SemanticDiagnosticsBuilderProgram;
|
||||
|
||||
interface BuilderProgram {
|
||||
getProgram(): Program;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
getCurrentDirectory(): string;
|
||||
}
|
||||
|
||||
interface EmitAndSemanticDiagnosticsBuilderProgram extends BuilderProgram {
|
||||
getSemanticDiagnosticsOfNextAffectedFile(
|
||||
cancellationToken?: CancellationToken,
|
||||
ignoreSourceFile?: (sourceFile: SourceFile) => boolean
|
||||
): AffectedFileResult<readonly Diagnostic[]>;
|
||||
emit(
|
||||
targetSourceFile?: SourceFile,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
): EmitResult | undefined;
|
||||
getAllDependencies(sourceFile: SourceFile): readonly string[];
|
||||
getSyntacticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly Diagnostic[];
|
||||
getSemanticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly Diagnostic[];
|
||||
}
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const host = ts.createIncrementalCompilerHost({
|
||||
target: ts.ScriptTarget.ES2020,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
incremental: true,
|
||||
tsBuildInfoFile: '.tsbuildinfo'
|
||||
});
|
||||
|
||||
const program = ts.createIncrementalProgram({
|
||||
rootNames: ['index.ts', 'utils.ts'],
|
||||
options: {
|
||||
target: ts.ScriptTarget.ES2020,
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
incremental: true
|
||||
},
|
||||
host
|
||||
});
|
||||
|
||||
let result = program.emit();
|
||||
```
|
||||
|
||||
## Watch Program
|
||||
|
||||
Watch mode compilation.
|
||||
|
||||
```typescript { .api }
|
||||
function createWatchCompilerHost<T extends BuilderProgram>(
|
||||
rootFiles: string[],
|
||||
options: CompilerOptions,
|
||||
system: System,
|
||||
createProgram?: CreateProgram<T>,
|
||||
reportDiagnostic?: DiagnosticReporter,
|
||||
reportWatchStatus?: WatchStatusReporter,
|
||||
watchOptionsToExtend?: WatchOptions,
|
||||
extraFileExtensions?: readonly FileExtensionInfo[]
|
||||
): WatchCompilerHostOfFilesAndCompilerOptions<T>;
|
||||
|
||||
function createWatchProgram<T extends BuilderProgram>(
|
||||
host: WatchCompilerHostOfFilesAndCompilerOptions<T>
|
||||
): WatchOfFilesAndCompilerOptions<T>;
|
||||
|
||||
interface WatchCompilerHost<T extends BuilderProgram> {
|
||||
afterProgramCreate?(program: T): void;
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getNewLine(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
getDefaultLibLocation?(): string;
|
||||
createHash?(data: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
readFile(path: string, encoding?: string): string | undefined;
|
||||
directoryExists?(path: string): boolean;
|
||||
getDirectories?(path: string): string[];
|
||||
readDirectory?(
|
||||
path: string,
|
||||
extensions?: readonly string[],
|
||||
exclude?: readonly string[],
|
||||
include?: readonly string[],
|
||||
depth?: number
|
||||
): string[];
|
||||
watchFile(
|
||||
path: string,
|
||||
callback: FileWatcherCallback,
|
||||
pollingInterval?: number,
|
||||
options?: WatchOptions
|
||||
): FileWatcher;
|
||||
watchDirectory(
|
||||
path: string,
|
||||
callback: DirectoryWatcherCallback,
|
||||
recursive?: boolean,
|
||||
options?: WatchOptions
|
||||
): FileWatcher;
|
||||
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
|
||||
clearTimeout?(timeoutId: any): void;
|
||||
}
|
||||
```
|
||||
|
||||
## Project References
|
||||
|
||||
Multi-project compilation support.
|
||||
|
||||
```typescript { .api }
|
||||
interface ProjectReference {
|
||||
path: string;
|
||||
originalPath?: string;
|
||||
prepend?: boolean;
|
||||
circular?: boolean;
|
||||
}
|
||||
|
||||
interface ResolvedProjectReference {
|
||||
commandLine: ParsedCommandLine;
|
||||
sourceFile: SourceFile;
|
||||
references?: readonly (ResolvedProjectReference | undefined)[];
|
||||
}
|
||||
```
|
||||
|
||||
## Enumerations
|
||||
|
||||
```typescript { .api }
|
||||
enum ScriptTarget {
|
||||
ES3 = 0,
|
||||
ES5 = 1,
|
||||
ES2015 = 2,
|
||||
ES2016 = 3,
|
||||
ES2017 = 4,
|
||||
ES2018 = 5,
|
||||
ES2019 = 6,
|
||||
ES2020 = 7,
|
||||
ES2021 = 8,
|
||||
ES2022 = 9,
|
||||
ES2023 = 10,
|
||||
ES2024 = 11,
|
||||
ESNext = 99,
|
||||
JSON = 100,
|
||||
Latest = 99
|
||||
}
|
||||
|
||||
enum ModuleKind {
|
||||
None = 0,
|
||||
CommonJS = 1,
|
||||
AMD = 2,
|
||||
UMD = 3,
|
||||
System = 4,
|
||||
ES2015 = 5,
|
||||
ES2020 = 6,
|
||||
ES2022 = 7,
|
||||
ESNext = 99,
|
||||
Node16 = 100,
|
||||
Node18 = 101,
|
||||
Node20 = 102,
|
||||
NodeNext = 199,
|
||||
Preserve = 200
|
||||
}
|
||||
|
||||
enum ModuleResolutionKind {
|
||||
Classic = 1,
|
||||
NodeJs = 2,
|
||||
Node16 = 3,
|
||||
NodeNext = 99,
|
||||
Bundler = 100
|
||||
}
|
||||
|
||||
enum ModuleDetectionKind {
|
||||
Legacy = 1,
|
||||
Auto = 2,
|
||||
Force = 3
|
||||
}
|
||||
|
||||
enum JsxEmit {
|
||||
None = 0,
|
||||
Preserve = 1,
|
||||
React = 2,
|
||||
ReactNative = 3,
|
||||
ReactJSX = 4,
|
||||
ReactJSXDev = 5
|
||||
}
|
||||
|
||||
enum NewLineKind {
|
||||
CarriageReturnLineFeed = 0,
|
||||
LineFeed = 1
|
||||
}
|
||||
```
|
||||
|
||||
115
.tessl/tiles/tessl/npm-typescript/docs/core/config.md
Normal file
115
.tessl/tiles/tessl/npm-typescript/docs/core/config.md
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
# Configuration Parsing
|
||||
|
||||
Parse TypeScript configuration files (tsconfig.json).
|
||||
|
||||
## Configuration Parsing APIs
|
||||
|
||||
```typescript { .api }
|
||||
function findConfigFile(
|
||||
searchPath: string,
|
||||
fileExists: (fileName: string) => boolean,
|
||||
configName?: string
|
||||
): string | undefined;
|
||||
|
||||
function parseJsonConfigFileContent(
|
||||
json: any,
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
existingOptions?: CompilerOptions,
|
||||
configFileName?: string,
|
||||
resolutionStack?: Path[],
|
||||
extraFileExtensions?: readonly FileExtensionInfo[],
|
||||
extendedConfigCache?: Map<string, ExtendedConfigCacheEntry>,
|
||||
existingWatchOptions?: WatchOptions
|
||||
): ParsedCommandLine;
|
||||
|
||||
function parseJsonSourceFileConfigFileContent(
|
||||
sourceFile: TsConfigSourceFile,
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
existingOptions?: CompilerOptions,
|
||||
configFileName?: string,
|
||||
resolutionStack?: Path[],
|
||||
extraFileExtensions?: readonly FileExtensionInfo[],
|
||||
extendedConfigCache?: Map<string, ExtendedConfigCacheEntry>,
|
||||
existingWatchOptions?: WatchOptions
|
||||
): ParsedCommandLine;
|
||||
|
||||
function readConfigFile(
|
||||
fileName: string,
|
||||
readFile: (path: string) => string | undefined
|
||||
): { config?: any; error?: Diagnostic };
|
||||
|
||||
function getParsedCommandLineOfConfigFile(
|
||||
configFileName: string,
|
||||
optionsToExtend: CompilerOptions | undefined,
|
||||
host: ParseConfigFileHost,
|
||||
extendedConfigCache?: Map<string, ExtendedConfigCacheEntry>,
|
||||
watchOptionsToExtend?: WatchOptions,
|
||||
extraFileExtensions?: readonly FileExtensionInfo[]
|
||||
): ParsedCommandLine | undefined;
|
||||
|
||||
interface ParsedCommandLine {
|
||||
options: CompilerOptions;
|
||||
typeAcquisition?: TypeAcquisition;
|
||||
fileNames: string[];
|
||||
projectReferences?: readonly ProjectReference[];
|
||||
watchOptions?: WatchOptions;
|
||||
raw?: any;
|
||||
errors: Diagnostic[];
|
||||
wildcardDirectories?: MapLike<WatchDirectoryFlags>;
|
||||
compileOnSave?: boolean;
|
||||
}
|
||||
|
||||
interface ParseConfigHost {
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
readDirectory(
|
||||
rootDir: string,
|
||||
extensions: readonly string[],
|
||||
excludes: readonly string[] | undefined,
|
||||
includes: readonly string[],
|
||||
depth?: number
|
||||
): readonly string[];
|
||||
fileExists(path: string): boolean;
|
||||
readFile(path: string): string | undefined;
|
||||
trace?(s: string): void;
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
// Find config file
|
||||
const configPath = ts.findConfigFile(
|
||||
'./src',
|
||||
ts.sys.fileExists
|
||||
);
|
||||
|
||||
if (configPath) {
|
||||
// Read config file
|
||||
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
||||
|
||||
if (configFile.config) {
|
||||
// Parse config
|
||||
const parsed = ts.parseJsonConfigFileContent(
|
||||
configFile.config,
|
||||
{
|
||||
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
||||
readDirectory: ts.sys.readDirectory,
|
||||
fileExists: ts.sys.fileExists,
|
||||
readFile: ts.sys.readFile
|
||||
},
|
||||
ts.getDirectoryPath(configPath)
|
||||
);
|
||||
|
||||
// Use parsed options
|
||||
const program = ts.createProgram({
|
||||
rootNames: parsed.fileNames,
|
||||
options: parsed.options
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
241
.tessl/tiles/tessl/npm-typescript/docs/core/module-resolution.md
Normal file
241
.tessl/tiles/tessl/npm-typescript/docs/core/module-resolution.md
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
# Module Resolution
|
||||
|
||||
APIs for resolving module imports and type reference directives with support for multiple resolution strategies.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Module Name Resolution
|
||||
|
||||
Resolve module names to file paths.
|
||||
|
||||
```typescript { .api }
|
||||
function resolveModuleName(
|
||||
moduleName: string,
|
||||
containingFile: string,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleResolutionHost,
|
||||
cache?: ModuleResolutionCache,
|
||||
redirectedReference?: ResolvedProjectReference,
|
||||
resolutionMode?: ResolutionMode
|
||||
): ResolvedModuleWithFailedLookupLocations;
|
||||
|
||||
function nodeModuleNameResolver(
|
||||
moduleName: string,
|
||||
containingFile: string,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleResolutionHost,
|
||||
cache?: ModuleResolutionCache,
|
||||
redirectedReference?: ResolvedProjectReference
|
||||
): ResolvedModuleWithFailedLookupLocations;
|
||||
|
||||
function classicNameResolver(
|
||||
moduleName: string,
|
||||
containingFile: string,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleResolutionHost,
|
||||
cache?: NonRelativeModuleNameResolutionCache | undefined,
|
||||
redirectedReference?: ResolvedProjectReference
|
||||
): ResolvedModuleWithFailedLookupLocations;
|
||||
|
||||
function bundlerModuleNameResolver(
|
||||
moduleName: string,
|
||||
containingFile: string,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleResolutionHost,
|
||||
cache?: ModuleResolutionCache,
|
||||
redirectedReference?: ResolvedProjectReference
|
||||
): ResolvedModuleWithFailedLookupLocations;
|
||||
```
|
||||
|
||||
### Type Reference Directive Resolution
|
||||
|
||||
Resolve type reference directives.
|
||||
|
||||
```typescript { .api }
|
||||
function resolveTypeReferenceDirective(
|
||||
typeReferenceDirectiveName: string,
|
||||
containingFile: string | undefined,
|
||||
compilerOptions: CompilerOptions,
|
||||
host: ModuleResolutionHost,
|
||||
redirectedReference?: ResolvedProjectReference,
|
||||
cache?: TypeReferenceDirectiveResolutionCache,
|
||||
resolutionMode?: ResolutionMode
|
||||
): ResolvedTypeReferenceDirectiveWithFailedLookupLocations;
|
||||
```
|
||||
|
||||
### Module Resolution Host
|
||||
|
||||
Interface for file system operations during resolution.
|
||||
|
||||
```typescript { .api }
|
||||
interface ModuleResolutionHost {
|
||||
fileExists(fileName: string): boolean;
|
||||
readFile(fileName: string): string | undefined;
|
||||
trace?(s: string): void;
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
realpath?(path: string): string;
|
||||
getCurrentDirectory?(): string;
|
||||
getDirectories?(path: string): string[];
|
||||
useCaseSensitiveFileNames?: boolean | (() => boolean) | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Resolved Module
|
||||
|
||||
Result of module resolution.
|
||||
|
||||
```typescript { .api }
|
||||
interface ResolvedModule {
|
||||
resolvedFileName: string;
|
||||
isExternalLibraryImport?: boolean;
|
||||
resolvedUsingTsExtension?: boolean;
|
||||
}
|
||||
|
||||
interface ResolvedModuleFull extends ResolvedModule {
|
||||
extension: string;
|
||||
packageId?: PackageId;
|
||||
}
|
||||
|
||||
interface ResolvedModuleWithFailedLookupLocations {
|
||||
readonly resolvedModule: ResolvedModuleFull | undefined;
|
||||
}
|
||||
|
||||
interface PackageId {
|
||||
name: string;
|
||||
subModuleName: string;
|
||||
version: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Type Reference Directive
|
||||
|
||||
```typescript { .api }
|
||||
interface ResolvedTypeReferenceDirective {
|
||||
primary: boolean;
|
||||
resolvedFileName: string | undefined;
|
||||
packageId?: PackageId;
|
||||
isExternalLibraryImport?: boolean;
|
||||
}
|
||||
|
||||
interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
|
||||
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Module Resolution Cache
|
||||
|
||||
Cache for module resolution results.
|
||||
|
||||
```typescript { .api }
|
||||
function createModuleResolutionCache(
|
||||
currentDirectory: string,
|
||||
getCanonicalFileName: (s: string) => string,
|
||||
options?: CompilerOptions
|
||||
): ModuleResolutionCache;
|
||||
|
||||
interface ModuleResolutionCache {
|
||||
getPackageJsonInfoCache(): PackageJsonInfoCache;
|
||||
}
|
||||
|
||||
function createTypeReferenceDirectiveResolutionCache(
|
||||
currentDirectory: string,
|
||||
getCanonicalFileName: (s: string) => string,
|
||||
options?: CompilerOptions,
|
||||
packageJsonInfoCache?: PackageJsonInfoCache
|
||||
): TypeReferenceDirectiveResolutionCache;
|
||||
|
||||
interface TypeReferenceDirectiveResolutionCache {
|
||||
getOrCreateCacheForDirectory(directoryName: string, redirectedReference?: ResolvedProjectReference): PerDirectoryResolutionCache<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>;
|
||||
}
|
||||
```
|
||||
|
||||
### File Extensions
|
||||
|
||||
```typescript { .api }
|
||||
enum Extension {
|
||||
Ts = ".ts",
|
||||
Tsx = ".tsx",
|
||||
Dts = ".d.ts",
|
||||
Js = ".js",
|
||||
Jsx = ".jsx",
|
||||
Json = ".json",
|
||||
TsBuildInfo = ".tsbuildinfo",
|
||||
Mjs = ".mjs",
|
||||
Mts = ".mts",
|
||||
Dmts = ".d.mts",
|
||||
Cjs = ".cjs",
|
||||
Cts = ".cts",
|
||||
Dcts = ".d.cts"
|
||||
}
|
||||
|
||||
interface FileExtensionInfo {
|
||||
extension: string;
|
||||
isMixedContent: boolean;
|
||||
scriptKind?: ScriptKind;
|
||||
}
|
||||
```
|
||||
|
||||
### Resolution Mode
|
||||
|
||||
```typescript { .api }
|
||||
type ResolutionMode = ModuleKind.CommonJS | ModuleKind.ESNext;
|
||||
|
||||
function getModeForFileReference(ref: FileReference | string, containingFileMode: ResolutionMode): ResolutionMode;
|
||||
function getModeForUsageLocation(file: SourceFile, usage: StringLiteralLike): ResolutionMode;
|
||||
function getModeForResolutionAtIndex(file: SourceFile, index: number): ResolutionMode;
|
||||
```
|
||||
|
||||
### Type Roots
|
||||
|
||||
```typescript { .api }
|
||||
function getEffectiveTypeRoots(
|
||||
options: CompilerOptions,
|
||||
host: GetEffectiveTypeRootsHost
|
||||
): string[] | undefined;
|
||||
|
||||
interface GetEffectiveTypeRootsHost {
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
getCurrentDirectory?(): string;
|
||||
}
|
||||
```
|
||||
|
||||
### Automatic Type Acquisition
|
||||
|
||||
```typescript { .api }
|
||||
function getAutomaticTypeDirectiveNames(
|
||||
options: CompilerOptions,
|
||||
host: ModuleResolutionHost
|
||||
): string[];
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
Resolving a module name:
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
const compilerOptions: ts.CompilerOptions = {
|
||||
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
||||
target: ts.ScriptTarget.ES2020,
|
||||
module: ts.ModuleKind.CommonJS
|
||||
};
|
||||
|
||||
const host: ts.ModuleResolutionHost = {
|
||||
fileExists: (fileName: string) => ts.sys.fileExists(fileName),
|
||||
readFile: (fileName: string) => ts.sys.readFile(fileName)
|
||||
};
|
||||
|
||||
const result = ts.resolveModuleName(
|
||||
'lodash',
|
||||
'/project/src/index.ts',
|
||||
compilerOptions,
|
||||
host
|
||||
);
|
||||
|
||||
if (result.resolvedModule) {
|
||||
console.log('Resolved to:', result.resolvedModule.resolvedFileName);
|
||||
console.log('Extension:', result.resolvedModule.extension);
|
||||
console.log('Is external:', result.resolvedModule.isExternalLibraryImport);
|
||||
}
|
||||
```
|
||||
401
.tessl/tiles/tessl/npm-typescript/docs/core/solution-builder.md
Normal file
401
.tessl/tiles/tessl/npm-typescript/docs/core/solution-builder.md
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
# Solution Builder
|
||||
|
||||
Solution Builder provides APIs for building TypeScript projects with project references, enabling efficient compilation of large codebases and monorepos through incremental builds and dependency management.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Solution Builder Creation
|
||||
|
||||
Create solution builders for building projects with project references.
|
||||
|
||||
```typescript { .api }
|
||||
/**
|
||||
* Create a solution builder host for non-watch mode compilation
|
||||
* @param system - System interface for file operations
|
||||
* @param createProgram - Optional custom program creator
|
||||
* @param reportDiagnostic - Optional diagnostic reporter
|
||||
* @param reportSolutionBuilderStatus - Optional status reporter
|
||||
* @param reportErrorSummary - Optional error summary reporter
|
||||
* @returns Solution builder host instance
|
||||
*/
|
||||
function createSolutionBuilderHost<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(
|
||||
system?: System,
|
||||
createProgram?: CreateProgram<T>,
|
||||
reportDiagnostic?: DiagnosticReporter,
|
||||
reportSolutionBuilderStatus?: DiagnosticReporter,
|
||||
reportErrorSummary?: ReportEmitErrorSummary
|
||||
): SolutionBuilderHost<T>;
|
||||
|
||||
/**
|
||||
* Create a solution builder host with file watching capabilities
|
||||
* @param system - System interface for file operations
|
||||
* @param createProgram - Optional custom program creator
|
||||
* @param reportDiagnostic - Optional diagnostic reporter
|
||||
* @param reportSolutionBuilderStatus - Optional status reporter
|
||||
* @param reportWatchStatus - Optional watch status reporter
|
||||
* @returns Solution builder host with watch capabilities
|
||||
*/
|
||||
function createSolutionBuilderWithWatchHost<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(
|
||||
system?: System,
|
||||
createProgram?: CreateProgram<T>,
|
||||
reportDiagnostic?: DiagnosticReporter,
|
||||
reportSolutionBuilderStatus?: DiagnosticReporter,
|
||||
reportWatchStatus?: WatchStatusReporter
|
||||
): SolutionBuilderWithWatchHost<T>;
|
||||
|
||||
/**
|
||||
* Create a solution builder for building multiple projects
|
||||
* @param host - Solution builder host
|
||||
* @param rootNames - Array of project config file paths
|
||||
* @param defaultOptions - Default build options
|
||||
* @returns Solution builder instance
|
||||
*/
|
||||
function createSolutionBuilder<T extends BuilderProgram>(
|
||||
host: SolutionBuilderHost<T>,
|
||||
rootNames: readonly string[],
|
||||
defaultOptions: BuildOptions
|
||||
): SolutionBuilder<T>;
|
||||
|
||||
/**
|
||||
* Create a solution builder with file watching
|
||||
* @param host - Solution builder host with watch capabilities
|
||||
* @param rootNames - Array of project config file paths
|
||||
* @param defaultOptions - Default build options
|
||||
* @param baseWatchOptions - Optional watch configuration
|
||||
* @returns Solution builder instance with watch mode
|
||||
*/
|
||||
function createSolutionBuilderWithWatch<T extends BuilderProgram>(
|
||||
host: SolutionBuilderWithWatchHost<T>,
|
||||
rootNames: readonly string[],
|
||||
defaultOptions: BuildOptions,
|
||||
baseWatchOptions?: WatchOptions
|
||||
): SolutionBuilder<T>;
|
||||
|
||||
/**
|
||||
* Create a diagnostic reporter for builder status messages
|
||||
* @param system - System interface for output
|
||||
* @param pretty - Whether to use colored output
|
||||
* @returns Diagnostic reporter function
|
||||
*/
|
||||
function createBuilderStatusReporter(
|
||||
system: System,
|
||||
pretty?: boolean
|
||||
): DiagnosticReporter;
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
// Create diagnostic reporter (simple function implementing DiagnosticReporter type)
|
||||
const diagnosticReporter: ts.DiagnosticReporter = (diagnostic) => {
|
||||
console.error(ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
|
||||
};
|
||||
|
||||
// Create a solution builder host
|
||||
const host = ts.createSolutionBuilderHost(
|
||||
ts.sys,
|
||||
undefined,
|
||||
diagnosticReporter,
|
||||
ts.createBuilderStatusReporter(ts.sys, true),
|
||||
(errorCount) => console.log(`Errors: ${errorCount}`)
|
||||
);
|
||||
|
||||
// Create the solution builder
|
||||
const builder = ts.createSolutionBuilder(
|
||||
host,
|
||||
['./packages/app/tsconfig.json', './packages/lib/tsconfig.json'],
|
||||
{ verbose: true }
|
||||
);
|
||||
|
||||
// Build all projects
|
||||
const exitStatus = builder.build();
|
||||
```
|
||||
|
||||
### Solution Builder Interface
|
||||
|
||||
Main interface for building and cleaning projects with project references.
|
||||
|
||||
```typescript { .api }
|
||||
interface SolutionBuilder<T extends BuilderProgram> {
|
||||
/**
|
||||
* Build a specific project or all projects
|
||||
* @param project - Optional project path to build (builds all if not specified)
|
||||
* @param cancellationToken - Optional cancellation token
|
||||
* @param writeFile - Optional custom file writer
|
||||
* @param getCustomTransformers - Optional custom transformer provider
|
||||
* @returns Exit status code
|
||||
*/
|
||||
build(
|
||||
project?: string,
|
||||
cancellationToken?: CancellationToken,
|
||||
writeFile?: WriteFileCallback,
|
||||
getCustomTransformers?: (project: string) => CustomTransformers
|
||||
): ExitStatus;
|
||||
|
||||
/**
|
||||
* Clean build outputs for a project or all projects
|
||||
* @param project - Optional project path to clean (cleans all if not specified)
|
||||
* @returns Exit status code
|
||||
*/
|
||||
clean(project?: string): ExitStatus;
|
||||
|
||||
/**
|
||||
* Build only the project references of a specific project
|
||||
* @param project - Project path
|
||||
* @param cancellationToken - Optional cancellation token
|
||||
* @param writeFile - Optional custom file writer
|
||||
* @param getCustomTransformers - Optional custom transformer provider
|
||||
* @returns Exit status code
|
||||
*/
|
||||
buildReferences(
|
||||
project: string,
|
||||
cancellationToken?: CancellationToken,
|
||||
writeFile?: WriteFileCallback,
|
||||
getCustomTransformers?: (project: string) => CustomTransformers
|
||||
): ExitStatus;
|
||||
|
||||
/**
|
||||
* Clean build outputs for project references
|
||||
* @param project - Optional project path
|
||||
* @returns Exit status code
|
||||
*/
|
||||
cleanReferences(project?: string): ExitStatus;
|
||||
|
||||
/**
|
||||
* Get the next invalidated project that needs to be built
|
||||
* @param cancellationToken - Optional cancellation token
|
||||
* @returns Next invalidated project or undefined if all up-to-date
|
||||
*/
|
||||
getNextInvalidatedProject(
|
||||
cancellationToken?: CancellationToken
|
||||
): InvalidatedProject<T> | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Build Options
|
||||
|
||||
Configuration options for solution builder builds.
|
||||
|
||||
```typescript { .api }
|
||||
interface BuildOptions {
|
||||
/** Perform a dry run without writing files */
|
||||
dry?: boolean;
|
||||
/** Force rebuild all projects even if up-to-date */
|
||||
force?: boolean;
|
||||
/** Enable verbose logging */
|
||||
verbose?: boolean;
|
||||
/** Stop building on first error */
|
||||
stopBuildOnErrors?: boolean;
|
||||
/** Enable incremental compilation */
|
||||
incremental?: boolean;
|
||||
/** Assume changes only affect direct dependencies */
|
||||
assumeChangesOnlyAffectDirectDependencies?: boolean;
|
||||
/** Emit declaration files */
|
||||
declaration?: boolean;
|
||||
/** Emit declaration source maps */
|
||||
declarationMap?: boolean;
|
||||
/** Only emit declaration files */
|
||||
emitDeclarationOnly?: boolean;
|
||||
/** Emit source maps */
|
||||
sourceMap?: boolean;
|
||||
/** Emit inline source maps */
|
||||
inlineSourceMap?: boolean;
|
||||
/** Enable trace resolution logging */
|
||||
traceResolution?: boolean;
|
||||
/** Additional compiler options */
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Solution Builder Host
|
||||
|
||||
Host interface providing file system operations for solution builder.
|
||||
|
||||
```typescript { .api }
|
||||
interface SolutionBuilderHostBase<T extends BuilderProgram> extends ProgramHost<T> {
|
||||
/** Create a directory */
|
||||
createDirectory?(path: string): void;
|
||||
|
||||
/** Write a file to disk */
|
||||
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
|
||||
/** Get custom transformers for a project */
|
||||
getCustomTransformers?: (project: string) => CustomTransformers | undefined;
|
||||
|
||||
/** Get the last modified time of a file */
|
||||
getModifiedTime(fileName: string): Date | undefined;
|
||||
|
||||
/** Set the modified time of a file */
|
||||
setModifiedTime(fileName: string, date: Date): void;
|
||||
|
||||
/** Delete a file */
|
||||
deleteFile(fileName: string): void;
|
||||
|
||||
/** Get parsed command line for a project */
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
|
||||
/** Report diagnostic messages */
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
|
||||
/** Report solution builder status messages */
|
||||
reportSolutionBuilderStatus: DiagnosticReporter;
|
||||
|
||||
/** Hook called after program emit and diagnostics */
|
||||
afterProgramEmitAndDiagnostics?(program: T): void;
|
||||
}
|
||||
|
||||
interface SolutionBuilderHost<T extends BuilderProgram> extends SolutionBuilderHostBase<T> {
|
||||
/** Report error summary */
|
||||
reportErrorSummary?: ReportEmitErrorSummary;
|
||||
}
|
||||
|
||||
interface SolutionBuilderWithWatchHost<T extends BuilderProgram>
|
||||
extends SolutionBuilderHostBase<T>, WatchHost {}
|
||||
|
||||
type ReportEmitErrorSummary = (
|
||||
errorCount: number,
|
||||
filesInError: (ReportFileInError | undefined)[]
|
||||
) => void;
|
||||
|
||||
interface ReportFileInError {
|
||||
fileName: string;
|
||||
line: number;
|
||||
}
|
||||
```
|
||||
|
||||
### Invalidated Projects
|
||||
|
||||
Interfaces for working with projects that need to be rebuilt.
|
||||
|
||||
```typescript { .api }
|
||||
enum InvalidatedProjectKind {
|
||||
/** Project needs to be built */
|
||||
Build = 0,
|
||||
/** Only output file timestamps need updating */
|
||||
UpdateOutputFileStamps = 1
|
||||
}
|
||||
|
||||
interface InvalidatedProjectBase {
|
||||
/** Type of invalidation */
|
||||
readonly kind: InvalidatedProjectKind;
|
||||
|
||||
/** Resolved config file name */
|
||||
readonly project: ResolvedConfigFileName;
|
||||
|
||||
/**
|
||||
* Complete building this project and update state
|
||||
* @param cancellationToken - Optional cancellation token
|
||||
* @param writeFile - Optional custom file writer
|
||||
* @param customTransformers - Optional custom transformers
|
||||
* @returns Exit status code
|
||||
*/
|
||||
done(
|
||||
cancellationToken?: CancellationToken,
|
||||
writeFile?: WriteFileCallback,
|
||||
customTransformers?: CustomTransformers
|
||||
): ExitStatus;
|
||||
|
||||
/** Get compiler options for this project */
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
|
||||
/** Get current directory for this project */
|
||||
getCurrentDirectory(): string;
|
||||
}
|
||||
|
||||
interface UpdateOutputFileStampsProject extends InvalidatedProjectBase {
|
||||
readonly kind: InvalidatedProjectKind.UpdateOutputFileStamps;
|
||||
|
||||
/**
|
||||
* Update output file timestamps without rebuilding
|
||||
* @note Method name contains typo in TypeScript source (missing 'p' in "Stamps")
|
||||
*/
|
||||
updateOutputFileStatmps(): void;
|
||||
}
|
||||
|
||||
interface BuildInvalidedProject<T extends BuilderProgram> extends InvalidatedProjectBase {
|
||||
readonly kind: InvalidatedProjectKind.Build;
|
||||
|
||||
/** Get the builder program */
|
||||
getBuilderProgram(): T | undefined;
|
||||
|
||||
/** Get the program */
|
||||
getProgram(): Program | undefined;
|
||||
|
||||
/** Get a source file by name */
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
|
||||
/** Get all source files */
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
|
||||
/** Get options diagnostics */
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
|
||||
/** Get global diagnostics */
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
|
||||
/** Get config file parsing diagnostics */
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
|
||||
/** Get syntactic diagnostics */
|
||||
getSyntacticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly Diagnostic[];
|
||||
|
||||
/** Get all dependencies of a source file */
|
||||
getAllDependencies(sourceFile: SourceFile): readonly string[];
|
||||
|
||||
/** Get semantic diagnostics */
|
||||
getSemanticDiagnostics(
|
||||
sourceFile?: SourceFile,
|
||||
cancellationToken?: CancellationToken
|
||||
): readonly Diagnostic[];
|
||||
|
||||
/** Get semantic diagnostics of next affected file */
|
||||
getSemanticDiagnosticsOfNextAffectedFile(
|
||||
cancellationToken?: CancellationToken,
|
||||
ignoreSourceFile?: (sourceFile: SourceFile) => boolean
|
||||
): AffectedFileResult<readonly Diagnostic[]>;
|
||||
|
||||
/** Emit JavaScript and declaration files */
|
||||
emit(
|
||||
targetSourceFile?: SourceFile,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
): EmitResult | undefined;
|
||||
}
|
||||
|
||||
type InvalidatedProject<T extends BuilderProgram> =
|
||||
| UpdateOutputFileStampsProject
|
||||
| BuildInvalidedProject<T>;
|
||||
```
|
||||
|
||||
### Utilities
|
||||
|
||||
Utility functions for working with solution builder.
|
||||
|
||||
```typescript { .api }
|
||||
/**
|
||||
* Check if command line arguments indicate a build command
|
||||
* @param commandLineArgs - Command line arguments
|
||||
* @returns True if this is a --build command
|
||||
*/
|
||||
function isBuildCommand(commandLineArgs: readonly string[]): boolean;
|
||||
```
|
||||
|
||||
**Usage Example:**
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
|
||||
// Check if this is a build command
|
||||
if (ts.isBuildCommand(process.argv.slice(2))) {
|
||||
// Parse as build command
|
||||
const parsedBuildCommand = ts.parseBuildCommand(process.argv.slice(2));
|
||||
// ... create solution builder and build
|
||||
}
|
||||
```
|
||||
373
.tessl/tiles/tessl/npm-typescript/docs/index.md
Normal file
373
.tessl/tiles/tessl/npm-typescript/docs/index.md
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
# TypeScript Compiler API
|
||||
|
||||
TypeScript v5.9.3 provides a comprehensive compiler API with 1,683+ public API members for programmatically analyzing, transforming, and emitting JavaScript code.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Installation and Import
|
||||
|
||||
```typescript
|
||||
import * as ts from 'typescript';
|
||||
// or
|
||||
const ts = require('typescript');
|
||||
```
|
||||
|
||||
### Essential Pattern
|
||||
|
||||
```typescript { .api }
|
||||
import * as ts from 'typescript';
|
||||
|
||||
// 1. Parse source code into AST
|
||||
const sourceFile = ts.createSourceFile(
|
||||
'example.ts',
|
||||
'const x: number = 42;',
|
||||
ts.ScriptTarget.Latest,
|
||||
true
|
||||
);
|
||||
|
||||
// 2. Create program for type checking
|
||||
const program = ts.createProgram({
|
||||
rootNames: ['example.ts'],
|
||||
options: { target: ts.ScriptTarget.ES2020 }
|
||||
});
|
||||
|
||||
// 3. Get type checker
|
||||
const checker = program.getTypeChecker();
|
||||
|
||||
// 4. Traverse AST
|
||||
function visit(node: ts.Node) {
|
||||
console.log(ts.SyntaxKind[node.kind]);
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
visit(sourceFile);
|
||||
|
||||
// 5. Emit JavaScript
|
||||
const emitResult = program.emit();
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Task: Parse and Analyze Code
|
||||
|
||||
**Goal**: Parse TypeScript source code and analyze its structure.
|
||||
|
||||
**Pattern**:
|
||||
1. Use `createSourceFile()` to parse code into AST
|
||||
2. Use `createProgram()` for type checking
|
||||
3. Use `program.getTypeChecker()` for type analysis
|
||||
4. Traverse AST with `forEachChild()` or `visitNode()`
|
||||
|
||||
**APIs**:
|
||||
- `createSourceFile()` - Parse source text into AST
|
||||
- `createProgram()` - Create compilation program
|
||||
- `program.getTypeChecker()` - Get type checker for semantic analysis
|
||||
- `forEachChild()` - Traverse AST nodes
|
||||
|
||||
**See**: [Core Compilation APIs](./core/compilation.md) | [AST Nodes](./ast/nodes.md) | [Type System](./types/type-checker.md)
|
||||
|
||||
### Task: Transform Code
|
||||
|
||||
**Goal**: Modify TypeScript code programmatically.
|
||||
|
||||
**Pattern**:
|
||||
1. Create transformer factory function
|
||||
2. Use `transform()` or integrate with `program.emit()` via `CustomTransformers`
|
||||
3. Use `TransformationContext.factory` to create/modify nodes
|
||||
4. Use `visitEachChild()` to traverse and transform
|
||||
|
||||
**APIs**:
|
||||
- `transform()` - Apply transformers to source files
|
||||
- `TransformerFactory` - Create custom transformers
|
||||
- `TransformationContext.factory` - Node factory for transformations
|
||||
- `visitEachChild()` - Visit and transform child nodes
|
||||
|
||||
**See**: [Transformation](./transformation/transformers.md) | [Node Factory](./ast/factory.md)
|
||||
|
||||
### Task: Generate Code
|
||||
|
||||
**Goal**: Programmatically generate TypeScript code.
|
||||
|
||||
**Pattern**:
|
||||
1. Use `factory` constant to create AST nodes
|
||||
2. Build complete AST structure
|
||||
3. Use `Printer` to convert AST to source code
|
||||
4. Or use `program.emit()` to generate JavaScript
|
||||
|
||||
**APIs**:
|
||||
- `factory` - Node factory (300+ methods)
|
||||
- `createPrinter()` - Create printer for AST to source conversion
|
||||
- `program.emit()` - Emit JavaScript output
|
||||
|
||||
**See**: [Node Factory](./ast/factory.md) | [Utilities](./utilities/printer.md)
|
||||
|
||||
### Task: Provide IDE Features
|
||||
|
||||
**Goal**: Implement editor features like completions, diagnostics, refactorings.
|
||||
|
||||
**Pattern**:
|
||||
1. Create `LanguageServiceHost` implementation
|
||||
2. Use `createLanguageService()` to create service
|
||||
3. Call methods like `getCompletionsAtPosition()`, `getQuickInfoAtPosition()`
|
||||
4. Update host when files change
|
||||
|
||||
**APIs**:
|
||||
- `createLanguageService()` - Create language service
|
||||
- `LanguageService` - 100+ methods for IDE features
|
||||
- `LanguageServiceHost` - Host interface for file operations
|
||||
|
||||
**See**: [Language Service](./language-service/api.md)
|
||||
|
||||
### Task: Resolve Modules
|
||||
|
||||
**Goal**: Resolve module imports and type references.
|
||||
|
||||
**Pattern**:
|
||||
1. Use `resolveModuleName()` for module resolution
|
||||
2. Use `resolveTypeReferenceDirective()` for type references
|
||||
3. Implement `ModuleResolutionHost` for file system operations
|
||||
4. Use `ModuleResolutionCache` for performance
|
||||
|
||||
**APIs**:
|
||||
- `resolveModuleName()` - Resolve module imports
|
||||
- `resolveTypeReferenceDirective()` - Resolve type references
|
||||
- `ModuleResolutionHost` - File system interface
|
||||
|
||||
**See**: [Module Resolution](./core/module-resolution.md)
|
||||
|
||||
### Task: Build Projects
|
||||
|
||||
**Goal**: Build TypeScript projects with incremental compilation.
|
||||
|
||||
**Pattern**:
|
||||
1. Use `createSolutionBuilder()` for multi-project builds
|
||||
2. Configure project references in tsconfig.json
|
||||
3. Use incremental compilation with `BuilderProgram`
|
||||
4. Handle diagnostics and emit results
|
||||
|
||||
**APIs**:
|
||||
- `createSolutionBuilder()` - Multi-project builds
|
||||
- `createIncrementalProgram()` - Incremental compilation
|
||||
- `BuilderProgram` - Incremental program interface
|
||||
|
||||
**See**: [Solution Builder](./core/solution-builder.md) | [Core Compilation](./core/compilation.md)
|
||||
|
||||
## Core Architecture
|
||||
|
||||
TypeScript's compiler API consists of these major subsystems:
|
||||
|
||||
1. **Parser & Scanner**: Lexical analysis and AST construction
|
||||
2. **Binder**: Symbol creation and scope analysis
|
||||
3. **Type Checker**: Type inference, checking, and semantic analysis
|
||||
4. **Transformer**: AST transformation pipeline
|
||||
5. **Emitter**: JavaScript and declaration file generation
|
||||
6. **Language Service**: Editor integration (completions, diagnostics, refactorings)
|
||||
7. **Module Resolution**: Resolving imports and type references
|
||||
8. **Server Protocol**: TSServer communication
|
||||
|
||||
## API Reference by Category
|
||||
|
||||
### Core Compilation
|
||||
- [Compilation APIs](./core/compilation.md) - Program creation, compilation, emit
|
||||
- [Module Resolution](./core/module-resolution.md) - Import and type resolution
|
||||
- [Solution Builder](./core/solution-builder.md) - Multi-project builds
|
||||
- [Configuration Parsing](./core/config.md) - tsconfig.json parsing
|
||||
|
||||
### AST Manipulation
|
||||
- [AST Nodes](./ast/nodes.md) - Node types and traversal (359 syntax kinds)
|
||||
- [Node Factory](./ast/factory.md) - Creating AST nodes (300+ methods)
|
||||
- [Scanner and Parser](./ast/scanner-parser.md) - Lexical analysis and parsing
|
||||
- [Type Guards](./ast/type-guards.md) - Type guard functions for all node types
|
||||
|
||||
### Type System
|
||||
- [Type Checker](./types/type-checker.md) - TypeChecker API (150+ methods)
|
||||
- [Types and Symbols](./types/types-symbols.md) - Type and Symbol interfaces
|
||||
- [Type Utilities](./types/utilities.md) - Type analysis utilities
|
||||
- [Diagnostics](./types/diagnostics.md) - Error reporting and diagnostics
|
||||
|
||||
### Code Transformation
|
||||
- [Transformers](./transformation/transformers.md) - AST transformation pipeline
|
||||
- [Transformation Context](./transformation/context.md) - Transformation context API
|
||||
- [Emit Helpers](./transformation/emit-helpers.md) - Runtime helper utilities
|
||||
|
||||
### Editor Integration
|
||||
- [Language Service](./language-service/api.md) - IDE features (100+ methods)
|
||||
- [Completions](./language-service/completions.md) - Code completion APIs
|
||||
- [Navigation](./language-service/navigation.md) - Go to definition, find references
|
||||
- [Refactorings](./language-service/refactorings.md) - Code refactoring APIs
|
||||
- [Formatting](./language-service/formatting.md) - Code formatting APIs
|
||||
- [TSServer Protocol](./language-service/tsserver.md) - Language server protocol
|
||||
|
||||
### Utilities
|
||||
- [System Interface](./utilities/system.md) - File system operations
|
||||
- [Printer](./utilities/printer.md) - AST to source code conversion
|
||||
- [Transpilation](./utilities/transpilation.md) - Quick TypeScript to JavaScript conversion
|
||||
- [Path Utilities](./utilities/paths.md) - Path manipulation functions
|
||||
- [Text Utilities](./utilities/text.md) - Text and position utilities
|
||||
|
||||
## Essential APIs
|
||||
|
||||
### Program Creation
|
||||
|
||||
```typescript { .api }
|
||||
function createProgram(
|
||||
rootNames: readonly string[],
|
||||
options: CompilerOptions,
|
||||
host?: CompilerHost,
|
||||
oldProgram?: Program,
|
||||
configFileParsingDiagnostics?: readonly Diagnostic[]
|
||||
): Program;
|
||||
|
||||
interface Program {
|
||||
getRootFileNames(): readonly string[];
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
getTypeChecker(): TypeChecker;
|
||||
emit(
|
||||
targetSourceFile?: SourceFile,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
): EmitResult;
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[];
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile): readonly Diagnostic[];
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
}
|
||||
```
|
||||
|
||||
### AST Nodes and Traversal
|
||||
|
||||
```typescript { .api }
|
||||
enum SyntaxKind {
|
||||
Unknown = 0,
|
||||
Identifier = 80,
|
||||
// ... 359 syntax kinds total
|
||||
}
|
||||
|
||||
interface Node {
|
||||
readonly kind: SyntaxKind;
|
||||
readonly flags: NodeFlags;
|
||||
readonly parent: Node;
|
||||
getSourceFile(): SourceFile;
|
||||
getText(sourceFile?: SourceFile): string;
|
||||
forEachChild<T>(cbNode: (node: Node) => T | undefined): T | undefined;
|
||||
}
|
||||
|
||||
function forEachChild<T>(
|
||||
node: Node,
|
||||
cbNode: (node: Node) => T | undefined
|
||||
): T | undefined;
|
||||
```
|
||||
|
||||
### Type System
|
||||
|
||||
```typescript { .api }
|
||||
interface TypeChecker {
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
getSymbolAtLocation(node: Node): Symbol | undefined;
|
||||
getTypeOfSymbolAtLocation(symbol: Symbol, node: Node): Type;
|
||||
getPropertiesOfType(type: Type): Symbol[];
|
||||
getSignaturesOfType(type: Type, kind: SignatureKind): readonly Signature[];
|
||||
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
|
||||
// ... 150+ more methods
|
||||
}
|
||||
|
||||
interface Type {
|
||||
flags: TypeFlags;
|
||||
symbol: Symbol;
|
||||
getProperties(): Symbol[];
|
||||
getCallSignatures(): readonly Signature[];
|
||||
}
|
||||
```
|
||||
|
||||
### Node Factory
|
||||
|
||||
```typescript { .api }
|
||||
const factory: NodeFactory;
|
||||
|
||||
interface NodeFactory {
|
||||
createSourceFile(statements: readonly Statement[], endOfFileToken: EndOfFileToken, flags: NodeFlags): SourceFile;
|
||||
createIdentifier(text: string): Identifier;
|
||||
createVariableStatement(modifiers: readonly Modifier[] | undefined, declarationList: VariableDeclarationList): VariableStatement;
|
||||
createFunctionDeclaration(modifiers: readonly ModifierLike[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: readonly TypeParameterDeclaration[] | undefined, parameters: readonly ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined): FunctionDeclaration;
|
||||
// ... 300+ more factory functions
|
||||
}
|
||||
```
|
||||
|
||||
### Language Service
|
||||
|
||||
```typescript { .api }
|
||||
function createLanguageService(
|
||||
host: LanguageServiceHost,
|
||||
documentRegistry?: DocumentRegistry,
|
||||
syntaxOnlyOrLanguageServiceMode?: boolean | LanguageServiceMode
|
||||
): LanguageService;
|
||||
|
||||
interface LanguageService {
|
||||
getCompletionsAtPosition(fileName: string, position: number, options?: GetCompletionsAtPositionOptions): WithMetadata<CompletionInfo> | undefined;
|
||||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo | undefined;
|
||||
getDefinitionAtPosition(fileName: string, position: number): readonly DefinitionInfo[] | undefined;
|
||||
findReferences(fileName: string, position: number): ReferencedSymbol[] | undefined;
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences?: UserPreferences): ApplicableRefactorInfo[];
|
||||
// ... 100+ more methods
|
||||
}
|
||||
```
|
||||
|
||||
### Transformation
|
||||
|
||||
```typescript { .api }
|
||||
type TransformerFactory<T extends Node> = (
|
||||
context: TransformationContext
|
||||
) => Transformer<T>;
|
||||
|
||||
type Transformer<T extends Node> = (node: T) => T;
|
||||
|
||||
interface TransformationContext {
|
||||
factory: NodeFactory;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
hoistFunctionDeclaration(node: FunctionDeclaration): void;
|
||||
hoistVariableDeclaration(node: Identifier): void;
|
||||
requestEmitHelper(helper: EmitHelper): void;
|
||||
enableSubstitution(kind: SyntaxKind): void;
|
||||
enableEmitNotification(kind: SyntaxKind): void;
|
||||
}
|
||||
|
||||
function transform<T extends Node>(
|
||||
source: T | T[],
|
||||
transformers: TransformerFactory<T>[],
|
||||
compilerOptions?: CompilerOptions
|
||||
): TransformationResult<T>;
|
||||
```
|
||||
|
||||
## Key Enumerations
|
||||
|
||||
- `SyntaxKind` (359 values) - All AST node types
|
||||
- `TypeFlags` - Type classification flags
|
||||
- `SymbolFlags` - Symbol classification flags
|
||||
- `ScriptTarget` - JavaScript target versions
|
||||
- `ModuleKind` - Module system types
|
||||
- `ModuleResolutionKind` - Module resolution strategies
|
||||
- `DiagnosticCategory` - Error, Warning, Suggestion, Message
|
||||
- `NodeFlags` - Node metadata flags
|
||||
|
||||
## Version Information
|
||||
|
||||
TypeScript v5.9.3 includes:
|
||||
- 64 enumerations
|
||||
- 803 interfaces
|
||||
- 269 type aliases
|
||||
- 510 functions
|
||||
- 21 constants
|
||||
- 10 classes
|
||||
- 6 namespaces
|
||||
|
||||
## Getting Help
|
||||
|
||||
For specific tasks:
|
||||
- **Parsing code**: See [Scanner and Parser](./ast/scanner-parser.md)
|
||||
- **Type checking**: See [Type System](./types/type-checker.md)
|
||||
- **Code transformation**: See [Transformation](./transformation/transformers.md)
|
||||
- **Building projects**: See [Solution Builder](./core/solution-builder.md)
|
||||
- **IDE features**: See [Language Service](./language-service/api.md)
|
||||
- **Module resolution**: See [Module Resolution](./core/module-resolution.md)
|
||||
|
||||
811
.tessl/tiles/tessl/npm-typescript/docs/language-service/api.md
Normal file
811
.tessl/tiles/tessl/npm-typescript/docs/language-service/api.md
Normal file
|
|
@ -0,0 +1,811 @@
|
|||
# Language Service
|
||||
|
||||
Language Service APIs for editor integration features including code completions, diagnostics, refactorings, and navigation. The LanguageService interface provides 100+ methods for IDE functionality.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### Language Service Creation
|
||||
|
||||
```typescript { .api }
|
||||
function createLanguageService(
|
||||
host: LanguageServiceHost,
|
||||
documentRegistry?: DocumentRegistry,
|
||||
syntaxOnlyOrLanguageServiceMode?: boolean | LanguageServiceMode
|
||||
): LanguageService;
|
||||
|
||||
function createDocumentRegistry(
|
||||
useCaseSensitiveFileNames?: boolean,
|
||||
currentDirectory?: string
|
||||
): DocumentRegistry;
|
||||
|
||||
enum LanguageServiceMode {
|
||||
Semantic = 0,
|
||||
PartialSemantic = 1,
|
||||
Syntactic = 2
|
||||
}
|
||||
|
||||
interface DocumentRegistry {
|
||||
acquireDocument(
|
||||
fileName: string,
|
||||
compilationSettingsOrHost: CompilerOptions | MinimalResolutionCacheHost,
|
||||
scriptSnapshot: IScriptSnapshot,
|
||||
version: string,
|
||||
scriptKind?: ScriptKind,
|
||||
sourceFileOptions?: CreateSourceFileOptions | ScriptTarget
|
||||
): SourceFile;
|
||||
|
||||
acquireDocumentWithKey(
|
||||
fileName: string,
|
||||
path: Path,
|
||||
compilationSettingsOrHost: CompilerOptions | MinimalResolutionCacheHost,
|
||||
key: DocumentRegistryBucketKey,
|
||||
scriptSnapshot: IScriptSnapshot,
|
||||
version: string,
|
||||
scriptKind?: ScriptKind,
|
||||
sourceFileOptions?: CreateSourceFileOptions | ScriptTarget
|
||||
): SourceFile;
|
||||
|
||||
updateDocument(
|
||||
fileName: string,
|
||||
compilationSettingsOrHost: CompilerOptions | MinimalResolutionCacheHost,
|
||||
scriptSnapshot: IScriptSnapshot,
|
||||
version: string,
|
||||
scriptKind?: ScriptKind,
|
||||
sourceFileOptions?: CreateSourceFileOptions | ScriptTarget
|
||||
): SourceFile;
|
||||
|
||||
updateDocumentWithKey(
|
||||
fileName: string,
|
||||
path: Path,
|
||||
compilationSettingsOrHost: CompilerOptions | MinimalResolutionCacheHost,
|
||||
key: DocumentRegistryBucketKey,
|
||||
scriptSnapshot: IScriptSnapshot,
|
||||
version: string,
|
||||
scriptKind?: ScriptKind,
|
||||
sourceFileOptions?: CreateSourceFileOptions | ScriptTarget
|
||||
): SourceFile;
|
||||
|
||||
releaseDocument(
|
||||
fileName: string,
|
||||
compilationSettings: CompilerOptions,
|
||||
scriptKind?: ScriptKind,
|
||||
impliedNodeFormat?: ResolutionMode
|
||||
): void;
|
||||
|
||||
releaseDocumentWithKey(
|
||||
path: Path,
|
||||
key: DocumentRegistryBucketKey,
|
||||
scriptKind?: ScriptKind,
|
||||
impliedNodeFormat?: ResolutionMode
|
||||
): void;
|
||||
|
||||
reportStats(): string;
|
||||
}
|
||||
```
|
||||
|
||||
### Language Service Interface
|
||||
|
||||
Main interface for editor functionality.
|
||||
|
||||
```typescript { .api }
|
||||
interface LanguageService {
|
||||
/* Cleanup */
|
||||
cleanupSemanticCache(): void;
|
||||
dispose(): void;
|
||||
|
||||
/* Diagnostics */
|
||||
getSyntacticDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
getSemanticDiagnostics(fileName: string): Diagnostic[];
|
||||
getSuggestionDiagnostics(fileName: string): DiagnosticWithLocation[];
|
||||
getCompilerOptionsDiagnostics(): Diagnostic[];
|
||||
|
||||
/* Completions */
|
||||
getCompletionsAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options: GetCompletionsAtPositionOptions | undefined,
|
||||
formattingSettings?: FormatCodeSettings
|
||||
): WithMetadata<CompletionInfo> | undefined;
|
||||
|
||||
getCompletionEntryDetails(
|
||||
fileName: string,
|
||||
position: number,
|
||||
entryName: string,
|
||||
formatOptions: FormatCodeOptions | FormatCodeSettings | undefined,
|
||||
source: string | undefined,
|
||||
preferences: UserPreferences | undefined,
|
||||
data: CompletionEntryData | undefined
|
||||
): CompletionEntryDetails | undefined;
|
||||
|
||||
getCompletionEntrySymbol(
|
||||
fileName: string,
|
||||
position: number,
|
||||
name: string,
|
||||
source: string | undefined
|
||||
): Symbol | undefined;
|
||||
|
||||
/* Quick Info */
|
||||
getQuickInfoAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
maximumLength?: number
|
||||
): QuickInfo | undefined;
|
||||
|
||||
getNameOrDottedNameSpan(
|
||||
fileName: string,
|
||||
startPos: number,
|
||||
endPos: number
|
||||
): TextSpan | undefined;
|
||||
|
||||
getBreakpointStatementAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): TextSpan | undefined;
|
||||
|
||||
/* Signature Help */
|
||||
getSignatureHelpItems(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options: SignatureHelpItemsOptions | undefined
|
||||
): SignatureHelpItems | undefined;
|
||||
|
||||
/* Rename */
|
||||
getRenameInfo(
|
||||
fileName: string,
|
||||
position: number,
|
||||
preferences: UserPreferences
|
||||
): RenameInfo;
|
||||
|
||||
findRenameLocations(
|
||||
fileName: string,
|
||||
position: number,
|
||||
findInStrings: boolean,
|
||||
findInComments: boolean,
|
||||
preferences: UserPreferences
|
||||
): readonly RenameLocation[] | undefined;
|
||||
|
||||
getSmartSelectionRange(
|
||||
fileName: string,
|
||||
position: number
|
||||
): SelectionRange;
|
||||
|
||||
/* Definitions */
|
||||
getDefinitionAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): readonly DefinitionInfo[] | undefined;
|
||||
|
||||
getDefinitionAndBoundSpan(
|
||||
fileName: string,
|
||||
position: number
|
||||
): DefinitionInfoAndBoundSpan | undefined;
|
||||
|
||||
getTypeDefinitionAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): readonly DefinitionInfo[] | undefined;
|
||||
|
||||
getImplementationAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): readonly ImplementationLocation[] | undefined;
|
||||
|
||||
/* References */
|
||||
getReferencesAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): ReferenceEntry[] | undefined;
|
||||
|
||||
findReferences(
|
||||
fileName: string,
|
||||
position: number
|
||||
): ReferencedSymbol[] | undefined;
|
||||
|
||||
getDocumentHighlights(
|
||||
fileName: string,
|
||||
position: number,
|
||||
filesToSearch: string[]
|
||||
): DocumentHighlights[] | undefined;
|
||||
|
||||
getFileReferences(fileName: string): ReferenceEntry[];
|
||||
|
||||
/* Navigation */
|
||||
getNavigateToItems(
|
||||
searchValue: string,
|
||||
maxResultCount?: number,
|
||||
fileName?: string,
|
||||
excludeDtsFiles?: boolean,
|
||||
excludeLibFiles?: boolean
|
||||
): NavigateToItem[];
|
||||
|
||||
getNavigationBarItems(fileName: string): NavigationBarItem[];
|
||||
getNavigationTree(fileName: string): NavigationTree;
|
||||
|
||||
/* Call Hierarchy */
|
||||
prepareCallHierarchy(
|
||||
fileName: string,
|
||||
position: number
|
||||
): CallHierarchyItem | CallHierarchyItem[] | undefined;
|
||||
|
||||
provideCallHierarchyIncomingCalls(
|
||||
fileName: string,
|
||||
position: number
|
||||
): CallHierarchyIncomingCall[];
|
||||
|
||||
provideCallHierarchyOutgoingCalls(
|
||||
fileName: string,
|
||||
position: number
|
||||
): CallHierarchyOutgoingCall[];
|
||||
|
||||
/* Inlay Hints */
|
||||
provideInlayHints(
|
||||
fileName: string,
|
||||
span: TextSpan,
|
||||
preferences: UserPreferences | undefined
|
||||
): InlayHint[];
|
||||
|
||||
/* Outlining */
|
||||
getOutliningSpans(fileName: string): OutliningSpan[];
|
||||
|
||||
/* TODOs */
|
||||
getTodoComments(
|
||||
fileName: string,
|
||||
descriptors: TodoCommentDescriptor[]
|
||||
): TodoComment[];
|
||||
|
||||
/* Brace Matching */
|
||||
getBraceMatchingAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): TextSpan[];
|
||||
|
||||
/* Indentation */
|
||||
getIndentationAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options: EditorOptions | EditorSettings
|
||||
): number;
|
||||
|
||||
/* Formatting */
|
||||
getFormattingEditsForRange(
|
||||
fileName: string,
|
||||
start: number,
|
||||
end: number,
|
||||
options: FormatCodeOptions | FormatCodeSettings
|
||||
): TextChange[];
|
||||
|
||||
getFormattingEditsForDocument(
|
||||
fileName: string,
|
||||
options: FormatCodeOptions | FormatCodeSettings
|
||||
): TextChange[];
|
||||
|
||||
getFormattingEditsAfterKeystroke(
|
||||
fileName: string,
|
||||
position: number,
|
||||
key: string,
|
||||
options: FormatCodeOptions | FormatCodeSettings
|
||||
): TextChange[];
|
||||
|
||||
/* JSDoc */
|
||||
getDocCommentTemplateAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options?: DocCommentTemplateOptions,
|
||||
formatOptions?: FormatCodeSettings
|
||||
): TextInsertion | undefined;
|
||||
|
||||
/* Brace Completion */
|
||||
isValidBraceCompletionAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
openingBrace: number
|
||||
): boolean;
|
||||
|
||||
/* JSX */
|
||||
getJsxClosingTagAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): JsxClosingTagInfo | undefined;
|
||||
|
||||
/* Linked Editing */
|
||||
getLinkedEditingRangeAtPosition(
|
||||
fileName: string,
|
||||
position: number
|
||||
): LinkedEditingInfo | undefined;
|
||||
|
||||
/* Span of Comment */
|
||||
getSpanOfEnclosingComment(
|
||||
fileName: string,
|
||||
position: number,
|
||||
onlyMultiLine: boolean
|
||||
): TextSpan | undefined;
|
||||
|
||||
/* Position Conversion */
|
||||
toLineColumnOffset?(
|
||||
fileName: string,
|
||||
position: number
|
||||
): LineAndCharacter;
|
||||
|
||||
/* Code Fixes */
|
||||
getCodeFixesAtPosition(
|
||||
fileName: string,
|
||||
start: number,
|
||||
end: number,
|
||||
errorCodes: readonly number[],
|
||||
formatOptions: FormatCodeSettings,
|
||||
preferences: UserPreferences
|
||||
): readonly CodeFixAction[];
|
||||
|
||||
getCombinedCodeFix(
|
||||
scope: CombinedCodeFixScope,
|
||||
fixId: {},
|
||||
formatOptions: FormatCodeSettings,
|
||||
preferences: UserPreferences
|
||||
): CombinedCodeActions;
|
||||
|
||||
applyCodeActionCommand(
|
||||
action: CodeActionCommand | CodeActionCommand[],
|
||||
formatSettings?: FormatCodeSettings
|
||||
): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
|
||||
getSupportedCodeFixes(fileName?: string): readonly string[];
|
||||
|
||||
/* Refactorings */
|
||||
getApplicableRefactors(
|
||||
fileName: string,
|
||||
positionOrRange: number | TextRange,
|
||||
preferences: UserPreferences | undefined,
|
||||
triggerReason?: RefactorTriggerReason,
|
||||
kind?: string,
|
||||
includeInteractiveActions?: boolean
|
||||
): ApplicableRefactorInfo[];
|
||||
|
||||
getEditsForRefactor(
|
||||
fileName: string,
|
||||
formatOptions: FormatCodeSettings,
|
||||
positionOrRange: number | TextRange,
|
||||
refactorName: string,
|
||||
actionName: string,
|
||||
preferences: UserPreferences | undefined,
|
||||
interactiveRefactorArguments?: InteractiveRefactorArguments
|
||||
): RefactorEditInfo | undefined;
|
||||
|
||||
getMoveToRefactoringFileSuggestions(
|
||||
fileName: string,
|
||||
positionOrRange: number | TextRange,
|
||||
preferences: UserPreferences | undefined,
|
||||
triggerReason?: RefactorTriggerReason,
|
||||
kind?: string
|
||||
): { newFileName: string; files: string[] };
|
||||
|
||||
/* Organize Imports */
|
||||
organizeImports(
|
||||
args: OrganizeImportsArgs,
|
||||
formatOptions: FormatCodeSettings,
|
||||
preferences: UserPreferences | undefined
|
||||
): readonly FileTextChanges[];
|
||||
|
||||
/* File Rename */
|
||||
getEditsForFileRename(
|
||||
oldFilePath: string,
|
||||
newFilePath: string,
|
||||
formatOptions: FormatCodeSettings,
|
||||
preferences: UserPreferences | undefined
|
||||
): readonly FileTextChanges[];
|
||||
|
||||
/* Emit */
|
||||
getEmitOutput(
|
||||
fileName: string,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
forceDtsEmit?: boolean
|
||||
): EmitOutput;
|
||||
|
||||
getProgram(): Program | undefined;
|
||||
|
||||
/* Comments */
|
||||
toggleLineComment(fileName: string, textRange: TextRange): TextChange[];
|
||||
toggleMultilineComment(fileName: string, textRange: TextRange): TextChange[];
|
||||
commentSelection(fileName: string, textRange: TextRange): TextChange[];
|
||||
uncommentSelection(fileName: string, textRange: TextRange): TextChange[];
|
||||
|
||||
/* Paste Edits */
|
||||
preparePasteEditsForFile(fileName: string, copiedTextRanges: TextRange[]): boolean;
|
||||
getPasteEdits(args: PasteEditsArgs, formatOptions: FormatCodeSettings): PasteEdits;
|
||||
|
||||
/* Classifications */
|
||||
getSyntacticClassifications(
|
||||
fileName: string,
|
||||
span: TextSpan,
|
||||
format: SemanticClassificationFormat
|
||||
): ClassifiedSpan[] | ClassifiedSpan2020[];
|
||||
|
||||
getSemanticClassifications(
|
||||
fileName: string,
|
||||
span: TextSpan,
|
||||
format: SemanticClassificationFormat
|
||||
): ClassifiedSpan[] | ClassifiedSpan2020[];
|
||||
|
||||
getEncodedSyntacticClassifications(
|
||||
fileName: string,
|
||||
span: TextSpan
|
||||
): Classifications;
|
||||
|
||||
getEncodedSemanticClassifications(
|
||||
fileName: string,
|
||||
span: TextSpan,
|
||||
format?: SemanticClassificationFormat
|
||||
): Classifications;
|
||||
}
|
||||
```
|
||||
|
||||
### Language Service Host
|
||||
|
||||
Host interface for file system operations.
|
||||
|
||||
```typescript { .api }
|
||||
interface LanguageServiceHost extends GetEffectiveTypeRootsHost, MinimalResolutionCacheHost {
|
||||
getCompilationSettings(): CompilerOptions;
|
||||
getNewLine?(): string;
|
||||
getProjectVersion?(): string;
|
||||
getScriptFileNames(): string[];
|
||||
getScriptKind?(fileName: string): ScriptKind;
|
||||
getScriptVersion(fileName: string): string;
|
||||
getScriptSnapshot(fileName: string): IScriptSnapshot | undefined;
|
||||
getProjectReferences?(): readonly ProjectReference[] | undefined;
|
||||
getLocalizedDiagnosticMessages?(): any;
|
||||
getCancellationToken?(): HostCancellationToken;
|
||||
getCurrentDirectory(): string;
|
||||
getDefaultLibFileName(options: CompilerOptions): string;
|
||||
log?(s: string): void;
|
||||
trace?(s: string): void;
|
||||
error?(s: string): void;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
readDirectory?(
|
||||
path: string,
|
||||
extensions?: readonly string[],
|
||||
exclude?: readonly string[],
|
||||
include?: readonly string[],
|
||||
depth?: number
|
||||
): string[];
|
||||
realpath?(path: string): string;
|
||||
readFile(path: string, encoding?: string): string | undefined;
|
||||
fileExists(path: string): boolean;
|
||||
getTypeRootsVersion?(): number;
|
||||
resolveModuleNameLiterals?(
|
||||
moduleLiterals: readonly StringLiteralLike[],
|
||||
containingFile: string,
|
||||
redirectedReference: ResolvedProjectReference | undefined,
|
||||
options: CompilerOptions,
|
||||
containingSourceFile: SourceFile,
|
||||
reusedNames: readonly StringLiteralLike[] | undefined
|
||||
): readonly ResolvedModuleWithFailedLookupLocations[];
|
||||
getResolvedModuleWithFailedLookupLocationsFromCache?(
|
||||
modulename: string,
|
||||
containingFile: string,
|
||||
resolutionMode?: ResolutionMode
|
||||
): ResolvedModuleWithFailedLookupLocations | undefined;
|
||||
resolveTypeReferenceDirectiveReferences?<T extends FileReference | string>(
|
||||
typeDirectiveReferences: readonly T[],
|
||||
containingFile: string,
|
||||
redirectedReference: ResolvedProjectReference | undefined,
|
||||
options: CompilerOptions,
|
||||
containingSourceFile: SourceFile | undefined,
|
||||
reusedNames: readonly T[] | undefined
|
||||
): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[];
|
||||
getDirectories?(directoryName: string): string[];
|
||||
getCustomTransformers?(): CustomTransformers | undefined;
|
||||
isKnownTypesPackageName?(name: string): boolean;
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
jsDocParsingMode?: JSDocParsingMode | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
### Completion Info
|
||||
|
||||
```typescript { .api }
|
||||
interface CompletionInfo {
|
||||
flags?: CompletionInfoFlags;
|
||||
isGlobalCompletion: boolean;
|
||||
isMemberCompletion: boolean;
|
||||
isNewIdentifierLocation: boolean;
|
||||
optionalReplacementSpan?: TextSpan;
|
||||
isIncomplete?: boolean;
|
||||
entries: CompletionEntry[];
|
||||
}
|
||||
|
||||
interface CompletionEntry {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers?: string;
|
||||
sortText: string;
|
||||
insertText?: string;
|
||||
filterText?: string;
|
||||
isSnippet?: boolean;
|
||||
replacementSpan?: TextSpan;
|
||||
hasAction?: true;
|
||||
source?: string;
|
||||
sourceDisplay?: SymbolDisplayPart[];
|
||||
labelDetails?: CompletionEntryLabelDetails;
|
||||
isRecommended?: true;
|
||||
isFromUncheckedFile?: true;
|
||||
isPackageJsonImport?: true;
|
||||
isImportStatementCompletion?: true;
|
||||
data?: CompletionEntryData;
|
||||
}
|
||||
|
||||
interface CompletionEntryDetails {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
displayParts: SymbolDisplayPart[];
|
||||
documentation?: SymbolDisplayPart[];
|
||||
tags?: JSDocTagInfo[];
|
||||
codeActions?: CodeAction[];
|
||||
source?: SymbolDisplayPart[];
|
||||
sourceDisplay?: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
interface GetCompletionsAtPositionOptions extends UserPreferences {
|
||||
triggerCharacter?: CompletionsTriggerCharacter;
|
||||
triggerKind?: CompletionTriggerKind;
|
||||
includeSymbol?: boolean;
|
||||
}
|
||||
|
||||
enum CompletionTriggerKind {
|
||||
Invoked = 1,
|
||||
TriggerCharacter = 2,
|
||||
TriggerForIncompleteCompletions = 3
|
||||
}
|
||||
```
|
||||
|
||||
### Signature Help
|
||||
|
||||
```typescript { .api }
|
||||
interface SignatureHelpItems {
|
||||
items: SignatureHelpItem[];
|
||||
applicableSpan: TextSpan;
|
||||
selectedItemIndex: number;
|
||||
argumentIndex: number;
|
||||
argumentCount: number;
|
||||
}
|
||||
|
||||
interface SignatureHelpItem {
|
||||
isVariadic: boolean;
|
||||
prefixDisplayParts: SymbolDisplayPart[];
|
||||
suffixDisplayParts: SymbolDisplayPart[];
|
||||
separatorDisplayParts: SymbolDisplayPart[];
|
||||
parameters: SignatureHelpParameter[];
|
||||
documentation: SymbolDisplayPart[];
|
||||
tags: JSDocTagInfo[];
|
||||
}
|
||||
|
||||
interface SignatureHelpParameter {
|
||||
name: string;
|
||||
documentation: SymbolDisplayPart[];
|
||||
displayParts: SymbolDisplayPart[];
|
||||
isOptional: boolean;
|
||||
isRest?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Quick Info
|
||||
|
||||
```typescript { .api }
|
||||
interface QuickInfo {
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
textSpan: TextSpan;
|
||||
displayParts?: SymbolDisplayPart[];
|
||||
documentation?: SymbolDisplayPart[];
|
||||
tags?: JSDocTagInfo[];
|
||||
canIncreaseVerbosityLevel?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Definition Info
|
||||
|
||||
```typescript { .api }
|
||||
interface DefinitionInfo extends DocumentSpan {
|
||||
kind: ScriptElementKind;
|
||||
name: string;
|
||||
containerKind: ScriptElementKind;
|
||||
containerName: string;
|
||||
unverified?: boolean;
|
||||
}
|
||||
|
||||
interface DefinitionInfoAndBoundSpan {
|
||||
definitions?: readonly DefinitionInfo[];
|
||||
textSpan: TextSpan;
|
||||
}
|
||||
|
||||
interface DocumentSpan {
|
||||
textSpan: TextSpan;
|
||||
fileName: string;
|
||||
originalTextSpan?: TextSpan;
|
||||
originalFileName?: string;
|
||||
contextSpan?: TextSpan;
|
||||
originalContextSpan?: TextSpan;
|
||||
}
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
```typescript { .api }
|
||||
interface ReferenceEntry extends DocumentSpan {
|
||||
isWriteAccess: boolean;
|
||||
isDefinition: boolean;
|
||||
isInString?: true;
|
||||
}
|
||||
|
||||
interface ReferencedSymbol {
|
||||
definition: ReferencedSymbolDefinitionInfo;
|
||||
references: ReferencedSymbolEntry[];
|
||||
}
|
||||
|
||||
interface ReferencedSymbolDefinitionInfo extends DefinitionInfo {
|
||||
displayParts: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
interface ReferencedSymbolEntry extends ReferenceEntry {
|
||||
isInString?: true;
|
||||
}
|
||||
```
|
||||
|
||||
### Rename Info
|
||||
|
||||
```typescript { .api }
|
||||
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
|
||||
|
||||
interface RenameInfoSuccess {
|
||||
canRename: true;
|
||||
fileToRename?: string;
|
||||
displayName: string;
|
||||
fullDisplayName: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
triggerSpan: TextSpan;
|
||||
}
|
||||
|
||||
interface RenameInfoFailure {
|
||||
canRename: false;
|
||||
localizedErrorMessage: string;
|
||||
}
|
||||
|
||||
interface RenameLocation extends DocumentSpan {
|
||||
prefixText?: string;
|
||||
suffixText?: string;
|
||||
}
|
||||
```
|
||||
|
||||
### Refactoring
|
||||
|
||||
```typescript { .api }
|
||||
interface ApplicableRefactorInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
actions: RefactorActionInfo[];
|
||||
inlineable?: boolean;
|
||||
}
|
||||
|
||||
interface RefactorActionInfo {
|
||||
name: string;
|
||||
description: string;
|
||||
notApplicableReason?: string;
|
||||
kind?: string;
|
||||
isInteractive?: boolean;
|
||||
}
|
||||
|
||||
interface RefactorEditInfo {
|
||||
edits: readonly FileTextChanges[];
|
||||
renameFilename?: string;
|
||||
renameLocation?: number;
|
||||
commands?: CodeActionCommand[];
|
||||
}
|
||||
|
||||
type RefactorTriggerReason = "implicit" | "invoked";
|
||||
```
|
||||
|
||||
### Code Actions
|
||||
|
||||
```typescript { .api }
|
||||
interface CodeAction {
|
||||
description: string;
|
||||
changes: FileTextChanges[];
|
||||
commands?: CodeActionCommand[];
|
||||
}
|
||||
|
||||
interface CodeFixAction extends CodeAction {
|
||||
fixName: string;
|
||||
fixId?: {};
|
||||
fixAllDescription?: string;
|
||||
}
|
||||
|
||||
interface CombinedCodeActions {
|
||||
changes: readonly FileTextChanges[];
|
||||
commands?: readonly CodeActionCommand[];
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
```typescript { .api }
|
||||
interface NavigationBarItem {
|
||||
text: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
spans: TextSpan[];
|
||||
childItems: NavigationBarItem[];
|
||||
indent: number;
|
||||
bolded: boolean;
|
||||
grayed: boolean;
|
||||
}
|
||||
|
||||
interface NavigationTree {
|
||||
text: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
spans: TextSpan[];
|
||||
nameSpan: TextSpan | undefined;
|
||||
childItems?: NavigationTree[];
|
||||
}
|
||||
|
||||
interface NavigateToItem {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
matchKind: "exact" | "prefix" | "substring" | "camelCase";
|
||||
isCaseSensitive: boolean;
|
||||
fileName: string;
|
||||
textSpan: TextSpan;
|
||||
containerName: string;
|
||||
containerKind: ScriptElementKind;
|
||||
}
|
||||
```
|
||||
|
||||
### User Preferences
|
||||
|
||||
```typescript { .api }
|
||||
interface UserPreferences {
|
||||
disableSuggestions?: boolean;
|
||||
quotePreference?: "auto" | "double" | "single";
|
||||
includeCompletionsForModuleExports?: boolean;
|
||||
includeCompletionsForImportStatements?: boolean;
|
||||
includeCompletionsWithSnippetText?: boolean;
|
||||
includeAutomaticOptionalChainCompletions?: boolean;
|
||||
includeCompletionsWithInsertText?: boolean;
|
||||
includeCompletionsWithClassMemberSnippets?: boolean;
|
||||
includeCompletionsWithObjectLiteralMethodSnippets?: boolean;
|
||||
useLabelDetailsInCompletionEntries?: boolean;
|
||||
allowIncompleteCompletions?: boolean;
|
||||
importModuleSpecifierPreference?: "shortest" | "project-relative" | "relative" | "non-relative";
|
||||
importModuleSpecifierEnding?: "auto" | "minimal" | "index" | "js";
|
||||
allowTextChangesInNewFiles?: boolean;
|
||||
providePrefixAndSuffixTextForRename?: boolean;
|
||||
provideRefactorNotApplicableReason?: boolean;
|
||||
includePackageJsonAutoImports?: "auto" | "on" | "off";
|
||||
jsxAttributeCompletionStyle?: "auto" | "braces" | "none";
|
||||
includeInlayParameterNameHints?: "none" | "literals" | "all";
|
||||
includeInlayParameterNameHintsWhenArgumentMatchesName?: boolean;
|
||||
includeInlayFunctionParameterTypeHints?: boolean;
|
||||
includeInlayVariableTypeHints?: boolean;
|
||||
includeInlayVariableTypeHintsWhenTypeMatchesName?: boolean;
|
||||
includeInlayPropertyDeclarationTypeHints?: boolean;
|
||||
includeInlayFunctionLikeReturnTypeHints?: boolean;
|
||||
includeInlayEnumMemberValueHints?: boolean;
|
||||
interactiveInlayHints?: boolean;
|
||||
allowRenameOfImportPath?: boolean;
|
||||
autoImportFileExcludePatterns?: string[];
|
||||
organizeImportsIgnoreCase?: "auto" | boolean;
|
||||
organizeImportsCollation?: "ordinal" | "unicode";
|
||||
organizeImportsLocale?: string;
|
||||
organizeImportsNumericCollation?: boolean;
|
||||
organizeImportsAccentCollation?: boolean;
|
||||
organizeImportsCaseFirst?: "upper" | "lower" | false;
|
||||
excludeLibrarySymbolsInNavTo?: boolean;
|
||||
lazyConfiguredProjectsFromExternalProject?: boolean;
|
||||
displayPartsForJSDoc?: boolean;
|
||||
generateReturnInDocTemplate?: boolean;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
# Code Completions
|
||||
|
||||
APIs for providing code completion suggestions in editors.
|
||||
|
||||
## Completion APIs
|
||||
|
||||
```typescript { .api }
|
||||
interface LanguageService {
|
||||
getCompletionsAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options: GetCompletionsAtPositionOptions | undefined,
|
||||
formattingSettings?: FormatCodeSettings
|
||||
): WithMetadata<CompletionInfo> | undefined;
|
||||
|
||||
getCompletionEntryDetails(
|
||||
fileName: string,
|
||||
position: number,
|
||||
entryName: string,
|
||||
formatOptions: FormatCodeOptions | FormatCodeSettings | undefined,
|
||||
source: string | undefined,
|
||||
preferences: UserPreferences | undefined,
|
||||
data: CompletionEntryData | undefined
|
||||
): CompletionEntryDetails | undefined;
|
||||
|
||||
getCompletionEntrySymbol(
|
||||
fileName: string,
|
||||
position: number,
|
||||
name: string,
|
||||
source: string | undefined
|
||||
): Symbol | undefined;
|
||||
}
|
||||
```
|
||||
|
||||
## Completion Info
|
||||
|
||||
```typescript { .api }
|
||||
interface CompletionInfo {
|
||||
flags?: CompletionInfoFlags;
|
||||
isGlobalCompletion: boolean;
|
||||
isMemberCompletion: boolean;
|
||||
isNewIdentifierLocation: boolean;
|
||||
optionalReplacementSpan?: TextSpan;
|
||||
isIncomplete?: boolean;
|
||||
entries: CompletionEntry[];
|
||||
}
|
||||
|
||||
interface CompletionEntry {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers?: string;
|
||||
sortText: string;
|
||||
insertText?: string;
|
||||
filterText?: string;
|
||||
isSnippet?: boolean;
|
||||
replacementSpan?: TextSpan;
|
||||
hasAction?: true;
|
||||
source?: string;
|
||||
sourceDisplay?: SymbolDisplayPart[];
|
||||
labelDetails?: CompletionEntryLabelDetails;
|
||||
isRecommended?: true;
|
||||
isFromUncheckedFile?: true;
|
||||
isPackageJsonImport?: true;
|
||||
isImportStatementCompletion?: true;
|
||||
data?: CompletionEntryData;
|
||||
}
|
||||
|
||||
interface CompletionEntryDetails {
|
||||
name: string;
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
displayParts: SymbolDisplayPart[];
|
||||
documentation?: SymbolDisplayPart[];
|
||||
tags?: JSDocTagInfo[];
|
||||
codeActions?: CodeAction[];
|
||||
source?: SymbolDisplayPart[];
|
||||
sourceDisplay?: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
interface GetCompletionsAtPositionOptions extends UserPreferences {
|
||||
triggerCharacter?: CompletionsTriggerCharacter;
|
||||
triggerKind?: CompletionTriggerKind;
|
||||
includeSymbol?: boolean;
|
||||
}
|
||||
|
||||
enum CompletionTriggerKind {
|
||||
Invoked = 1,
|
||||
TriggerCharacter = 2,
|
||||
TriggerForIncompleteCompletions = 3
|
||||
}
|
||||
```
|
||||
|
||||
## Signature Help
|
||||
|
||||
```typescript { .api }
|
||||
interface LanguageService {
|
||||
getSignatureHelpItems(
|
||||
fileName: string,
|
||||
position: number,
|
||||
options: SignatureHelpItemsOptions | undefined
|
||||
): SignatureHelpItems | undefined;
|
||||
}
|
||||
|
||||
interface SignatureHelpItems {
|
||||
items: SignatureHelpItem[];
|
||||
applicableSpan: TextSpan;
|
||||
selectedItemIndex: number;
|
||||
argumentIndex: number;
|
||||
argumentCount: number;
|
||||
}
|
||||
|
||||
interface SignatureHelpItem {
|
||||
isVariadic: boolean;
|
||||
prefixDisplayParts: SymbolDisplayPart[];
|
||||
suffixDisplayParts: SymbolDisplayPart[];
|
||||
separatorDisplayParts: SymbolDisplayPart[];
|
||||
parameters: SignatureHelpParameter[];
|
||||
documentation: SymbolDisplayPart[];
|
||||
tags?: JSDocTagInfo[];
|
||||
}
|
||||
|
||||
interface SignatureHelpParameter {
|
||||
name: string;
|
||||
documentation: SymbolDisplayPart[];
|
||||
displayParts: SymbolDisplayPart[];
|
||||
isOptional: boolean;
|
||||
isRest?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Info
|
||||
|
||||
```typescript { .api }
|
||||
interface LanguageService {
|
||||
getQuickInfoAtPosition(
|
||||
fileName: string,
|
||||
position: number,
|
||||
maximumLength?: number
|
||||
): QuickInfo | undefined;
|
||||
}
|
||||
|
||||
interface QuickInfo {
|
||||
kind: ScriptElementKind;
|
||||
kindModifiers: string;
|
||||
textSpan: TextSpan;
|
||||
displayParts?: SymbolDisplayPart[];
|
||||
documentation?: SymbolDisplayPart[];
|
||||
tags?: JSDocTagInfo[];
|
||||
canIncreaseVerbosityLevel?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue