oh-my-claudecode 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -4
- package/commands/necronomicon-bind.md +45 -82
- package/dist/agents/builtin-agents.d.ts.map +1 -1
- package/dist/agents/builtin-agents.js +8 -0
- package/dist/agents/builtin-agents.js.map +1 -1
- package/dist/agents/cthulhu.d.ts.map +1 -1
- package/dist/agents/cthulhu.js +11 -0
- package/dist/agents/cthulhu.js.map +1 -1
- package/dist/agents/dagon.d.ts.map +1 -1
- package/dist/agents/dagon.js +13 -0
- package/dist/agents/dagon.js.map +1 -1
- package/dist/agents/nodens-advanced.d.ts +182 -0
- package/dist/agents/nodens-advanced.d.ts.map +1 -0
- package/dist/agents/nodens-advanced.js +297 -0
- package/dist/agents/nodens-advanced.js.map +1 -0
- package/dist/agents/nodens.d.ts +42 -0
- package/dist/agents/nodens.d.ts.map +1 -0
- package/dist/agents/nodens.js +147 -0
- package/dist/agents/nodens.js.map +1 -0
- package/dist/agents/shoggoth.d.ts.map +1 -1
- package/dist/agents/shoggoth.js +11 -1
- package/dist/agents/shoggoth.js.map +1 -1
- package/dist/cli/bind.d.ts +24 -0
- package/dist/cli/bind.d.ts.map +1 -1
- package/dist/cli/bind.js +92 -25
- package/dist/cli/bind.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +7 -5
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +54 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.d.ts.map +1 -0
- package/dist/cli/version.js +28 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/config/schema.d.ts +648 -17
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +21 -2
- package/dist/config/schema.js.map +1 -1
- package/dist/features/web-research-background/advanced-patterns.d.ts +44 -0
- package/dist/features/web-research-background/advanced-patterns.d.ts.map +1 -0
- package/dist/features/web-research-background/advanced-patterns.js +139 -0
- package/dist/features/web-research-background/advanced-patterns.js.map +1 -0
- package/dist/features/web-research-background/index.d.ts +73 -0
- package/dist/features/web-research-background/index.d.ts.map +1 -0
- package/dist/features/web-research-background/index.js +131 -0
- package/dist/features/web-research-background/index.js.map +1 -0
- package/dist/features/yith-archive/functions/opencode-import.d.ts.map +1 -1
- package/dist/features/yith-archive/functions/opencode-import.js +129 -90
- package/dist/features/yith-archive/functions/opencode-import.js.map +1 -1
- package/dist/features/yith-archive/index.d.ts +8 -0
- package/dist/features/yith-archive/index.d.ts.map +1 -1
- package/dist/features/yith-archive/index.js +1 -0
- package/dist/features/yith-archive/index.js.map +1 -1
- package/dist/features/yith-archive/types.d.ts +15 -0
- package/dist/features/yith-archive/types.d.ts.map +1 -1
- package/dist/hooks/design-detector-hook.d.ts +12 -0
- package/dist/hooks/design-detector-hook.d.ts.map +1 -0
- package/dist/hooks/design-detector-hook.js +42 -0
- package/dist/hooks/design-detector-hook.js.map +1 -0
- package/dist/hooks/design-detector.d.ts +47 -0
- package/dist/hooks/design-detector.d.ts.map +1 -0
- package/dist/hooks/design-detector.js +251 -0
- package/dist/hooks/design-detector.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +27 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/web-research-detector.d.ts +58 -0
- package/dist/hooks/web-research-detector.d.ts.map +1 -0
- package/dist/hooks/web-research-detector.js +205 -0
- package/dist/hooks/web-research-detector.js.map +1 -0
- package/dist/hooks/web-research-hook.d.ts +12 -0
- package/dist/hooks/web-research-hook.d.ts.map +1 -0
- package/dist/hooks/web-research-hook.js +43 -0
- package/dist/hooks/web-research-hook.js.map +1 -0
- package/dist/hooks/yith-capture.d.ts +35 -0
- package/dist/hooks/yith-capture.d.ts.map +1 -0
- package/dist/hooks/yith-capture.js +113 -0
- package/dist/hooks/yith-capture.js.map +1 -0
- package/dist/linters/type-safety-ast.d.ts +108 -0
- package/dist/linters/type-safety-ast.d.ts.map +1 -0
- package/dist/linters/type-safety-ast.js +293 -0
- package/dist/linters/type-safety-ast.js.map +1 -0
- package/dist/linters/type-safety-linter.d.ts +66 -0
- package/dist/linters/type-safety-linter.d.ts.map +1 -0
- package/dist/linters/type-safety-linter.js +317 -0
- package/dist/linters/type-safety-linter.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Research Detector Hook
|
|
3
|
+
*
|
|
4
|
+
* PreToolUse hook that detects when user messages indicate a need for web research.
|
|
5
|
+
* Injects system context reminding agents about enforcing current knowledge.
|
|
6
|
+
*
|
|
7
|
+
* When triggered, it warns the agent that web research may be needed and suggests
|
|
8
|
+
* searching for current information before providing answers.
|
|
9
|
+
*/
|
|
10
|
+
export const WEB_RESEARCH_DETECTOR_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
11
|
+
# oh-my-claudecode: Web Research Detector PreToolUse Hook
|
|
12
|
+
# Fires on tool use to detect web research needs and inject enforcement context.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
CLAUDE_API_PROMPT="\${CLAUDE_API_PROMPT:-}"
|
|
17
|
+
|
|
18
|
+
# Extract a simple heuristic from the prompt: look for version patterns or date-sensitive keywords
|
|
19
|
+
# This is a bash-level heuristic that doesn't need the full TypeScript detector
|
|
20
|
+
|
|
21
|
+
# Check for version patterns: v1.0, 2024, latest, etc.
|
|
22
|
+
if echo "$CLAUDE_API_PROMPT" | grep -qiE '\\b(v[0-9]+\\.[0-9]+|20[0-9]{2}|latest\\s+(version|release|update)|breaking\\s+changes|what.?s\\s+new)\\b'; then
|
|
23
|
+
echo "[WEB RESEARCH ENFORCEMENT]"
|
|
24
|
+
echo "Detected request that may require current knowledge (version check, date-sensitive info)."
|
|
25
|
+
echo "If you don't have current information available, consider:"
|
|
26
|
+
echo " 1. Using WebSearch to find the latest information"
|
|
27
|
+
echo " 2. Checking official documentation for the most recent updates"
|
|
28
|
+
echo " 3. Being explicit about knowledge cutoff limitations"
|
|
29
|
+
echo ""
|
|
30
|
+
fi
|
|
31
|
+
`;
|
|
32
|
+
export function getWebResearchDetectorHookConfig() {
|
|
33
|
+
return {
|
|
34
|
+
matcher: "",
|
|
35
|
+
hooks: [
|
|
36
|
+
{
|
|
37
|
+
type: "command",
|
|
38
|
+
command: "~/.claude/hooks/web-research-detector.sh",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=web-research-hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-research-hook.js","sourceRoot":"","sources":["../../src/hooks/web-research-hook.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,iCAAiC,GAAG;;;;;;;;;;;;;;;;;;;;;CAqBhD,CAAA;AAED,MAAM,UAAU,gCAAgC;IAC9C,OAAO;QACL,OAAO,EAAE,EAAE;QACX,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,0CAA0C;aACpD;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yith-capture Stop hook — the continuous-ingestion layer for Yith
|
|
3
|
+
* Archive. Fires after every assistant turn (Claude Code's `Stop`
|
|
4
|
+
* event), spawns a fast `oh-my-claudecode bind --resume --claude-only`
|
|
5
|
+
* in the background, and — when the pending-compression queue is big
|
|
6
|
+
* enough — spawns a `claude -p` compression tick too. All spawns are
|
|
7
|
+
* detached so the assistant response never waits on them.
|
|
8
|
+
*
|
|
9
|
+
* Architecture notes:
|
|
10
|
+
*
|
|
11
|
+
* - Capture debounce (`.last-captured`, 5 seconds): the Stop event
|
|
12
|
+
* can fire many times in quick succession (one per assistant
|
|
13
|
+
* response in a long flow), and each bind tick does disk I/O +
|
|
14
|
+
* a fresh node start. 5 seconds is short enough to feel "live"
|
|
15
|
+
* and long enough to keep CPU usage bounded.
|
|
16
|
+
*
|
|
17
|
+
* - Compression debounce (`.last-compressed`, 5 minutes): running
|
|
18
|
+
* `claude -p` with a compression-batch prompt takes ~30 seconds
|
|
19
|
+
* of background work and uses the user's subscription. Firing it
|
|
20
|
+
* every 5 seconds would burn credits; firing it every 5 minutes
|
|
21
|
+
* catches the queue opportunistically without being invasive.
|
|
22
|
+
*
|
|
23
|
+
* - Compression threshold (50 pending observations): below this, we
|
|
24
|
+
* let the user's manual `/necronomicon-bind` ritual handle
|
|
25
|
+
* compression. Above it, we assume the queue is growing faster
|
|
26
|
+
* than the user is running the ritual and nudge the cron-style
|
|
27
|
+
* spawn path into action automatically.
|
|
28
|
+
*
|
|
29
|
+
* - Fail-safe: the hook exits 0 on every branch. A broken Yith
|
|
30
|
+
* install can never block the user's Claude Code session — the
|
|
31
|
+
* hook is purely additive.
|
|
32
|
+
*/
|
|
33
|
+
export declare const YITH_CAPTURE_HOOK_SCRIPT = "#!/usr/bin/env bash\n# oh-my-claudecode: Yith continuous-ingestion Stop hook\n# Runs after every assistant turn. Spawns background bind ticks to\n# keep raw observations flowing and (occasionally) to drain pending\n# compression via \\`claude -p\\`. Never blocks the session.\n\nset -euo pipefail\n\nYITH_DIR=\"${HOME}/.oh-my-claudecode/yith\"\nCAPTURE_SENTINEL=\"${YITH_DIR}/.last-captured\"\nCOMPRESS_SENTINEL=\"${YITH_DIR}/.last-compressed\"\nDEBOUNCE_CAPTURE_SEC=5\nDEBOUNCE_COMPRESS_SEC=300\nCOMPRESS_THRESHOLD=50\n\n# Bail early if Yith isn't installed yet (fresh machine, user hasn't\n# run \\`oh-my-claudecode bind\\` yet). The hook is strictly additive;\n# missing prerequisites are a silent no-op, not an error.\nif [ ! -d \"$YITH_DIR\" ]; then\n exit 0\nfi\n\n# Need the CLI on PATH to do anything useful.\nif ! command -v oh-my-claudecode >/dev/null 2>&1; then\n exit 0\nfi\n\nnow=$(date +%s)\n\n# \u2500\u2500 Capture tick (always tries to run) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlast_capture=0\nif [ -f \"$CAPTURE_SENTINEL\" ]; then\n last_capture=$(cat \"$CAPTURE_SENTINEL\" 2>/dev/null || echo 0)\nfi\n\nif [ $((now - last_capture)) -ge $DEBOUNCE_CAPTURE_SEC ]; then\n echo \"$now\" > \"$CAPTURE_SENTINEL\"\n # Scope the scan to the current project when CLAUDE_PROJECT_DIR is\n # set by Claude Code \u2014 otherwise let bind scan everything.\n PROJECT_FLAG=\"\"\n if [ -n \"${CLAUDE_PROJECT_DIR:-}\" ]; then\n PROJECT_FLAG=\"--project ${CLAUDE_PROJECT_DIR}\"\n fi\n # Fork-detach: the CLI's \\`--background\\` flag spawns a grandchild\n # with detached stdio and exits the parent immediately, so the Stop\n # hook returns in ~10 ms regardless of how long the backfill takes.\n oh-my-claudecode bind --resume --claude-only --background $PROJECT_FLAG \\\n >/dev/null 2>&1 || true\nfi\n\n# \u2500\u2500 Compression tick (threshold-gated, less frequent) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nNECRONOMICON=\"${YITH_DIR}/necronomicon.json\"\nif [ -f \"$NECRONOMICON\" ] && command -v jq >/dev/null 2>&1; then\n PENDING=$(jq -r '.\"mem:pending-compression\".state.count // 0' \"$NECRONOMICON\" 2>/dev/null || echo 0)\n if [ \"$PENDING\" -ge \"$COMPRESS_THRESHOLD\" ]; then\n last_compress=0\n if [ -f \"$COMPRESS_SENTINEL\" ]; then\n last_compress=$(cat \"$COMPRESS_SENTINEL\" 2>/dev/null || echo 0)\n fi\n if [ $((now - last_compress)) -ge $DEBOUNCE_COMPRESS_SEC ]; then\n echo \"$now\" > \"$COMPRESS_SENTINEL\"\n oh-my-claudecode bind --resume --compress-only --background \\\n >/dev/null 2>&1 || true\n fi\n fi\nfi\n\nexit 0\n";
|
|
34
|
+
export declare function getYithCaptureHookConfig(): object;
|
|
35
|
+
//# sourceMappingURL=yith-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yith-capture.d.ts","sourceRoot":"","sources":["../../src/hooks/yith-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,eAAO,MAAM,wBAAwB,2wFAoEpC,CAAA;AAED,wBAAgB,wBAAwB,IAAI,MAAM,CAUjD"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yith-capture Stop hook — the continuous-ingestion layer for Yith
|
|
3
|
+
* Archive. Fires after every assistant turn (Claude Code's `Stop`
|
|
4
|
+
* event), spawns a fast `oh-my-claudecode bind --resume --claude-only`
|
|
5
|
+
* in the background, and — when the pending-compression queue is big
|
|
6
|
+
* enough — spawns a `claude -p` compression tick too. All spawns are
|
|
7
|
+
* detached so the assistant response never waits on them.
|
|
8
|
+
*
|
|
9
|
+
* Architecture notes:
|
|
10
|
+
*
|
|
11
|
+
* - Capture debounce (`.last-captured`, 5 seconds): the Stop event
|
|
12
|
+
* can fire many times in quick succession (one per assistant
|
|
13
|
+
* response in a long flow), and each bind tick does disk I/O +
|
|
14
|
+
* a fresh node start. 5 seconds is short enough to feel "live"
|
|
15
|
+
* and long enough to keep CPU usage bounded.
|
|
16
|
+
*
|
|
17
|
+
* - Compression debounce (`.last-compressed`, 5 minutes): running
|
|
18
|
+
* `claude -p` with a compression-batch prompt takes ~30 seconds
|
|
19
|
+
* of background work and uses the user's subscription. Firing it
|
|
20
|
+
* every 5 seconds would burn credits; firing it every 5 minutes
|
|
21
|
+
* catches the queue opportunistically without being invasive.
|
|
22
|
+
*
|
|
23
|
+
* - Compression threshold (50 pending observations): below this, we
|
|
24
|
+
* let the user's manual `/necronomicon-bind` ritual handle
|
|
25
|
+
* compression. Above it, we assume the queue is growing faster
|
|
26
|
+
* than the user is running the ritual and nudge the cron-style
|
|
27
|
+
* spawn path into action automatically.
|
|
28
|
+
*
|
|
29
|
+
* - Fail-safe: the hook exits 0 on every branch. A broken Yith
|
|
30
|
+
* install can never block the user's Claude Code session — the
|
|
31
|
+
* hook is purely additive.
|
|
32
|
+
*/
|
|
33
|
+
export const YITH_CAPTURE_HOOK_SCRIPT = `#!/usr/bin/env bash
|
|
34
|
+
# oh-my-claudecode: Yith continuous-ingestion Stop hook
|
|
35
|
+
# Runs after every assistant turn. Spawns background bind ticks to
|
|
36
|
+
# keep raw observations flowing and (occasionally) to drain pending
|
|
37
|
+
# compression via \\\`claude -p\\\`. Never blocks the session.
|
|
38
|
+
|
|
39
|
+
set -euo pipefail
|
|
40
|
+
|
|
41
|
+
YITH_DIR="\${HOME}/.oh-my-claudecode/yith"
|
|
42
|
+
CAPTURE_SENTINEL="\${YITH_DIR}/.last-captured"
|
|
43
|
+
COMPRESS_SENTINEL="\${YITH_DIR}/.last-compressed"
|
|
44
|
+
DEBOUNCE_CAPTURE_SEC=5
|
|
45
|
+
DEBOUNCE_COMPRESS_SEC=300
|
|
46
|
+
COMPRESS_THRESHOLD=50
|
|
47
|
+
|
|
48
|
+
# Bail early if Yith isn't installed yet (fresh machine, user hasn't
|
|
49
|
+
# run \\\`oh-my-claudecode bind\\\` yet). The hook is strictly additive;
|
|
50
|
+
# missing prerequisites are a silent no-op, not an error.
|
|
51
|
+
if [ ! -d "\$YITH_DIR" ]; then
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# Need the CLI on PATH to do anything useful.
|
|
56
|
+
if ! command -v oh-my-claudecode >/dev/null 2>&1; then
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
now=\$(date +%s)
|
|
61
|
+
|
|
62
|
+
# ── Capture tick (always tries to run) ────────────────────────────────
|
|
63
|
+
last_capture=0
|
|
64
|
+
if [ -f "\$CAPTURE_SENTINEL" ]; then
|
|
65
|
+
last_capture=\$(cat "\$CAPTURE_SENTINEL" 2>/dev/null || echo 0)
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
if [ \$((now - last_capture)) -ge \$DEBOUNCE_CAPTURE_SEC ]; then
|
|
69
|
+
echo "\$now" > "\$CAPTURE_SENTINEL"
|
|
70
|
+
# Scope the scan to the current project when CLAUDE_PROJECT_DIR is
|
|
71
|
+
# set by Claude Code — otherwise let bind scan everything.
|
|
72
|
+
PROJECT_FLAG=""
|
|
73
|
+
if [ -n "\${CLAUDE_PROJECT_DIR:-}" ]; then
|
|
74
|
+
PROJECT_FLAG="--project \${CLAUDE_PROJECT_DIR}"
|
|
75
|
+
fi
|
|
76
|
+
# Fork-detach: the CLI's \\\`--background\\\` flag spawns a grandchild
|
|
77
|
+
# with detached stdio and exits the parent immediately, so the Stop
|
|
78
|
+
# hook returns in ~10 ms regardless of how long the backfill takes.
|
|
79
|
+
oh-my-claudecode bind --resume --claude-only --background \$PROJECT_FLAG \\
|
|
80
|
+
>/dev/null 2>&1 || true
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# ── Compression tick (threshold-gated, less frequent) ─────────────────
|
|
84
|
+
NECRONOMICON="\${YITH_DIR}/necronomicon.json"
|
|
85
|
+
if [ -f "\$NECRONOMICON" ] && command -v jq >/dev/null 2>&1; then
|
|
86
|
+
PENDING=\$(jq -r '."mem:pending-compression".state.count // 0' "\$NECRONOMICON" 2>/dev/null || echo 0)
|
|
87
|
+
if [ "\$PENDING" -ge "\$COMPRESS_THRESHOLD" ]; then
|
|
88
|
+
last_compress=0
|
|
89
|
+
if [ -f "\$COMPRESS_SENTINEL" ]; then
|
|
90
|
+
last_compress=\$(cat "\$COMPRESS_SENTINEL" 2>/dev/null || echo 0)
|
|
91
|
+
fi
|
|
92
|
+
if [ \$((now - last_compress)) -ge \$DEBOUNCE_COMPRESS_SEC ]; then
|
|
93
|
+
echo "\$now" > "\$COMPRESS_SENTINEL"
|
|
94
|
+
oh-my-claudecode bind --resume --compress-only --background \\
|
|
95
|
+
>/dev/null 2>&1 || true
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
exit 0
|
|
101
|
+
`;
|
|
102
|
+
export function getYithCaptureHookConfig() {
|
|
103
|
+
return {
|
|
104
|
+
matcher: "",
|
|
105
|
+
hooks: [
|
|
106
|
+
{
|
|
107
|
+
type: "command",
|
|
108
|
+
command: "~/.claude/hooks/yith-capture.sh",
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=yith-capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yith-capture.js","sourceRoot":"","sources":["../../src/hooks/yith-capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEvC,CAAA;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO;QACL,OAAO,EAAE,EAAE;QACX,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,iCAAiC;aAC3C;SACF;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-Based TypeScript Type Safety Linter
|
|
3
|
+
*
|
|
4
|
+
* Uses TypeScript compiler API to perform accurate type safety analysis:
|
|
5
|
+
* - Detects 'any' types in all contexts with zero false positives
|
|
6
|
+
* - Identifies missing return type annotations
|
|
7
|
+
* - Finds unsafe casts with context awareness
|
|
8
|
+
* - Validates Promise type parameters
|
|
9
|
+
* - Provides auto-fix capabilities for common issues
|
|
10
|
+
* - Tracks type safety metrics over time
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* AST-based type safety issue
|
|
14
|
+
*/
|
|
15
|
+
export interface ASTTypeSafetyIssue {
|
|
16
|
+
ruleId: string;
|
|
17
|
+
message: string;
|
|
18
|
+
line: number;
|
|
19
|
+
column: number;
|
|
20
|
+
severity: "error" | "warn" | "info";
|
|
21
|
+
fix?: string;
|
|
22
|
+
fixable?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Auto-fix result
|
|
26
|
+
*/
|
|
27
|
+
export interface AutoFixResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
message?: string;
|
|
30
|
+
originalCode?: string;
|
|
31
|
+
fixedCode?: string;
|
|
32
|
+
issuesFixed: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Type safety metrics
|
|
36
|
+
*/
|
|
37
|
+
export interface TypeSafetyMetrics {
|
|
38
|
+
totalFiles: number;
|
|
39
|
+
filesWithIssues: number;
|
|
40
|
+
totalIssues: number;
|
|
41
|
+
issuesByRule: Record<string, number>;
|
|
42
|
+
errorCount: number;
|
|
43
|
+
warningCount: number;
|
|
44
|
+
scorePercentage: number;
|
|
45
|
+
timestamp: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Linter configuration for AST mode
|
|
49
|
+
*/
|
|
50
|
+
export interface ASTLinterConfig {
|
|
51
|
+
enabled: boolean;
|
|
52
|
+
auto_fix?: boolean;
|
|
53
|
+
auto_fix_rules?: string[];
|
|
54
|
+
track_metrics?: boolean;
|
|
55
|
+
metrics_dir?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Lint TypeScript file using AST analysis
|
|
59
|
+
*
|
|
60
|
+
* @param filePath - Path to the TypeScript file
|
|
61
|
+
* @param config - Linter configuration
|
|
62
|
+
* @returns Array of type safety issues found
|
|
63
|
+
*/
|
|
64
|
+
export declare function lintFileAST(filePath: string, config?: ASTLinterConfig): ASTTypeSafetyIssue[];
|
|
65
|
+
/**
|
|
66
|
+
* Apply auto-fixes to a file
|
|
67
|
+
*
|
|
68
|
+
* @param filePath - Path to the TypeScript file
|
|
69
|
+
* @param issues - Issues to fix
|
|
70
|
+
* @param config - Configuration
|
|
71
|
+
* @returns Auto-fix result
|
|
72
|
+
*/
|
|
73
|
+
export declare function fixIssuesInFile(filePath: string, issues: ASTTypeSafetyIssue[], config?: ASTLinterConfig): AutoFixResult;
|
|
74
|
+
/**
|
|
75
|
+
* Generate type safety metrics for files
|
|
76
|
+
*
|
|
77
|
+
* @param filePaths - Array of file paths to analyze
|
|
78
|
+
* @param config - Configuration
|
|
79
|
+
* @returns Type safety metrics
|
|
80
|
+
*/
|
|
81
|
+
export declare function generateTypeMetrics(filePaths: string[], config?: ASTLinterConfig): TypeSafetyMetrics;
|
|
82
|
+
/**
|
|
83
|
+
* Export metrics to JSON file
|
|
84
|
+
*
|
|
85
|
+
* @param metrics - Metrics to export
|
|
86
|
+
* @param outputPath - Output file path
|
|
87
|
+
* @returns Success status
|
|
88
|
+
*/
|
|
89
|
+
export declare function exportMetrics(metrics: TypeSafetyMetrics, outputPath: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Load historical metrics
|
|
92
|
+
*
|
|
93
|
+
* @param metricsDir - Directory containing metrics files
|
|
94
|
+
* @returns Array of metrics in chronological order
|
|
95
|
+
*/
|
|
96
|
+
export declare function loadHistoricalMetrics(metricsDir: string): TypeSafetyMetrics[];
|
|
97
|
+
/**
|
|
98
|
+
* Calculate metrics trend
|
|
99
|
+
*
|
|
100
|
+
* @param metrics - Array of metrics in chronological order
|
|
101
|
+
* @returns Trend information
|
|
102
|
+
*/
|
|
103
|
+
export declare function calculateMetricsTrend(metrics: TypeSafetyMetrics[]): {
|
|
104
|
+
improvement: boolean;
|
|
105
|
+
percentChange: number;
|
|
106
|
+
description: string;
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=type-safety-ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-safety-ast.d.ts","sourceRoot":"","sources":["../../src/linters/type-safety-ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;IACnC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,kBAAkB,EAAE,CA+H5F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,EAAE,EAC5B,MAAM,CAAC,EAAE,eAAe,GACvB,aAAa,CA6Df;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EAAE,EACnB,MAAM,CAAC,EAAE,eAAe,GACvB,iBAAiB,CAkCnB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAYrF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAoB7E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG;IACnE,WAAW,EAAE,OAAO,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;CACpB,CAkBA"}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-Based TypeScript Type Safety Linter
|
|
3
|
+
*
|
|
4
|
+
* Uses TypeScript compiler API to perform accurate type safety analysis:
|
|
5
|
+
* - Detects 'any' types in all contexts with zero false positives
|
|
6
|
+
* - Identifies missing return type annotations
|
|
7
|
+
* - Finds unsafe casts with context awareness
|
|
8
|
+
* - Validates Promise type parameters
|
|
9
|
+
* - Provides auto-fix capabilities for common issues
|
|
10
|
+
* - Tracks type safety metrics over time
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import * as ts from "typescript";
|
|
15
|
+
/**
|
|
16
|
+
* Lint TypeScript file using AST analysis
|
|
17
|
+
*
|
|
18
|
+
* @param filePath - Path to the TypeScript file
|
|
19
|
+
* @param config - Linter configuration
|
|
20
|
+
* @returns Array of type safety issues found
|
|
21
|
+
*/
|
|
22
|
+
export function lintFileAST(filePath, config) {
|
|
23
|
+
if (!fs.existsSync(filePath)) {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
const sourceCode = fs.readFileSync(filePath, "utf-8");
|
|
27
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
28
|
+
const issues = [];
|
|
29
|
+
const lines = sourceCode.split("\n");
|
|
30
|
+
// Walk the AST and collect issues
|
|
31
|
+
const visit = (node) => {
|
|
32
|
+
// Check for 'any' type usage
|
|
33
|
+
if (ts.isTypeNode(node) && node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
34
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
35
|
+
issues.push({
|
|
36
|
+
ruleId: "TS_ANY_TYPE",
|
|
37
|
+
message: "Use of 'any' type is not allowed",
|
|
38
|
+
line: pos.line + 1,
|
|
39
|
+
column: pos.character + 1,
|
|
40
|
+
severity: "error",
|
|
41
|
+
fix: "Replace 'any' with specific type",
|
|
42
|
+
fixable: true,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// Check for unsafe type assertions
|
|
46
|
+
if (ts.isAsExpression(node)) {
|
|
47
|
+
const typeNode = node.type;
|
|
48
|
+
const typeText = typeNode.getText(sourceFile);
|
|
49
|
+
if (typeText === "any" ||
|
|
50
|
+
typeText === "unknown" ||
|
|
51
|
+
typeText.startsWith("Record<") ||
|
|
52
|
+
typeText === "{}") {
|
|
53
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
54
|
+
issues.push({
|
|
55
|
+
ruleId: "TS_UNSAFE_CAST",
|
|
56
|
+
message: `Unsafe cast to '${typeText}'`,
|
|
57
|
+
line: pos.line + 1,
|
|
58
|
+
column: pos.character + 1,
|
|
59
|
+
severity: "error",
|
|
60
|
+
fix: `Use type guard or specific type instead of '${typeText}'`,
|
|
61
|
+
fixable: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Check for missing return type annotations on functions
|
|
66
|
+
if ((ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) &&
|
|
67
|
+
!node.type &&
|
|
68
|
+
node.body) {
|
|
69
|
+
// Skip constructors and getters/setters
|
|
70
|
+
const isConstructor = ts.isFunctionDeclaration(node) && node.name?.text === "constructor";
|
|
71
|
+
const isGetterSetter = ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node);
|
|
72
|
+
if (!isConstructor && !isGetterSetter) {
|
|
73
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
74
|
+
issues.push({
|
|
75
|
+
ruleId: "MISSING_RETURN_TYPE",
|
|
76
|
+
message: "Function missing explicit return type annotation",
|
|
77
|
+
line: pos.line + 1,
|
|
78
|
+
column: pos.character + 1,
|
|
79
|
+
severity: "warn",
|
|
80
|
+
fix: "Add return type annotation to function",
|
|
81
|
+
fixable: false, // Would require inference
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Check for Promise without type parameter
|
|
86
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
87
|
+
const typeName = node.typeName;
|
|
88
|
+
if (ts.isIdentifier(typeName) && typeName.text === "Promise") {
|
|
89
|
+
if (!node.typeArguments || node.typeArguments.length === 0) {
|
|
90
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
91
|
+
issues.push({
|
|
92
|
+
ruleId: "MISSING_PROMISE_TYPE",
|
|
93
|
+
message: "Promise must have type parameter",
|
|
94
|
+
line: pos.line + 1,
|
|
95
|
+
column: pos.character + 1,
|
|
96
|
+
severity: "warn",
|
|
97
|
+
fix: "Add type parameter: Promise<T>",
|
|
98
|
+
fixable: false,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Check for @ts-ignore without reason
|
|
104
|
+
const precedingComments = ts.getLeadingCommentRanges(sourceCode, node.getFullStart());
|
|
105
|
+
if (precedingComments) {
|
|
106
|
+
for (const range of precedingComments) {
|
|
107
|
+
const comment = sourceCode.substring(range.pos, range.end);
|
|
108
|
+
if (comment.includes("@ts-ignore") && !comment.includes("@ts-ignore -")) {
|
|
109
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(range.pos);
|
|
110
|
+
issues.push({
|
|
111
|
+
ruleId: "TS_IGNORE_WITHOUT_REASON",
|
|
112
|
+
message: "@ts-ignore must have a reason comment",
|
|
113
|
+
line: pos.line + 1,
|
|
114
|
+
column: pos.character + 1,
|
|
115
|
+
severity: "warn",
|
|
116
|
+
fix: "Add reason: @ts-ignore - <reason>",
|
|
117
|
+
fixable: true,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
ts.forEachChild(node, visit);
|
|
123
|
+
};
|
|
124
|
+
visit(sourceFile);
|
|
125
|
+
return issues;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Apply auto-fixes to a file
|
|
129
|
+
*
|
|
130
|
+
* @param filePath - Path to the TypeScript file
|
|
131
|
+
* @param issues - Issues to fix
|
|
132
|
+
* @param config - Configuration
|
|
133
|
+
* @returns Auto-fix result
|
|
134
|
+
*/
|
|
135
|
+
export function fixIssuesInFile(filePath, issues, config) {
|
|
136
|
+
if (!fs.existsSync(filePath)) {
|
|
137
|
+
return { success: false, message: "File not found", issuesFixed: 0 };
|
|
138
|
+
}
|
|
139
|
+
const originalCode = fs.readFileSync(filePath, "utf-8");
|
|
140
|
+
let fixedCode = originalCode;
|
|
141
|
+
let issuesFixed = 0;
|
|
142
|
+
const fixableRules = config?.auto_fix_rules || [
|
|
143
|
+
"TS_ANY_TYPE",
|
|
144
|
+
"TS_UNSAFE_CAST",
|
|
145
|
+
"TS_IGNORE_WITHOUT_REASON",
|
|
146
|
+
];
|
|
147
|
+
const linesToFix = issues
|
|
148
|
+
.filter(issue => issue.fixable && fixableRules.includes(issue.ruleId))
|
|
149
|
+
.sort((a, b) => b.line - a.line); // Process from bottom to top to preserve positions
|
|
150
|
+
const lines = fixedCode.split("\n");
|
|
151
|
+
for (const issue of linesToFix) {
|
|
152
|
+
const lineIndex = issue.line - 1;
|
|
153
|
+
if (lineIndex >= 0 && lineIndex < lines.length) {
|
|
154
|
+
const line = lines[lineIndex];
|
|
155
|
+
// Apply fix based on rule
|
|
156
|
+
if (issue.ruleId === "TS_IGNORE_WITHOUT_REASON") {
|
|
157
|
+
if (line.includes("@ts-ignore") && !line.includes("@ts-ignore -")) {
|
|
158
|
+
lines[lineIndex] = line.replace(/@ts-ignore\b/, "@ts-ignore - complex type");
|
|
159
|
+
issuesFixed++;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (issue.ruleId === "TS_ANY_TYPE") {
|
|
163
|
+
// Replace simple 'any' with 'unknown'
|
|
164
|
+
if (line.includes(": any")) {
|
|
165
|
+
lines[lineIndex] = line.replace(/:\s*any\b/, ": unknown");
|
|
166
|
+
issuesFixed++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (issue.ruleId === "TS_UNSAFE_CAST") {
|
|
170
|
+
// Replace unsafe casts with 'unknown'
|
|
171
|
+
if (line.includes("as any")) {
|
|
172
|
+
lines[lineIndex] = line.replace(/\bas\s+any\b/, "as unknown");
|
|
173
|
+
issuesFixed++;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
fixedCode = lines.join("\n");
|
|
179
|
+
if (issuesFixed > 0) {
|
|
180
|
+
fs.writeFileSync(filePath, fixedCode, "utf-8");
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
success: issuesFixed > 0,
|
|
184
|
+
message: `Fixed ${issuesFixed} issues`,
|
|
185
|
+
originalCode,
|
|
186
|
+
fixedCode,
|
|
187
|
+
issuesFixed,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Generate type safety metrics for files
|
|
192
|
+
*
|
|
193
|
+
* @param filePaths - Array of file paths to analyze
|
|
194
|
+
* @param config - Configuration
|
|
195
|
+
* @returns Type safety metrics
|
|
196
|
+
*/
|
|
197
|
+
export function generateTypeMetrics(filePaths, config) {
|
|
198
|
+
const allIssues = [];
|
|
199
|
+
const filesWithIssues = new Set();
|
|
200
|
+
const issuesByRule = {};
|
|
201
|
+
for (const filePath of filePaths) {
|
|
202
|
+
const issues = lintFileAST(filePath, config);
|
|
203
|
+
if (issues.length > 0) {
|
|
204
|
+
filesWithIssues.add(filePath);
|
|
205
|
+
allIssues.push(...issues);
|
|
206
|
+
for (const issue of issues) {
|
|
207
|
+
issuesByRule[issue.ruleId] = (issuesByRule[issue.ruleId] || 0) + 1;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const errorCount = allIssues.filter(i => i.severity === "error").length;
|
|
212
|
+
const warningCount = allIssues.filter(i => i.severity === "warn").length;
|
|
213
|
+
// Calculate type safety score (0-100)
|
|
214
|
+
const maxIssues = filePaths.length * 10; // Arbitrary max issues per file
|
|
215
|
+
const scorePercentage = Math.max(0, 100 - (allIssues.length / maxIssues) * 100);
|
|
216
|
+
return {
|
|
217
|
+
totalFiles: filePaths.length,
|
|
218
|
+
filesWithIssues: filesWithIssues.size,
|
|
219
|
+
totalIssues: allIssues.length,
|
|
220
|
+
issuesByRule,
|
|
221
|
+
errorCount,
|
|
222
|
+
warningCount,
|
|
223
|
+
scorePercentage: Math.round(scorePercentage * 10) / 10,
|
|
224
|
+
timestamp: Date.now(),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Export metrics to JSON file
|
|
229
|
+
*
|
|
230
|
+
* @param metrics - Metrics to export
|
|
231
|
+
* @param outputPath - Output file path
|
|
232
|
+
* @returns Success status
|
|
233
|
+
*/
|
|
234
|
+
export function exportMetrics(metrics, outputPath) {
|
|
235
|
+
try {
|
|
236
|
+
const dir = path.dirname(outputPath);
|
|
237
|
+
if (!fs.existsSync(dir)) {
|
|
238
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
239
|
+
}
|
|
240
|
+
fs.writeFileSync(outputPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Load historical metrics
|
|
249
|
+
*
|
|
250
|
+
* @param metricsDir - Directory containing metrics files
|
|
251
|
+
* @returns Array of metrics in chronological order
|
|
252
|
+
*/
|
|
253
|
+
export function loadHistoricalMetrics(metricsDir) {
|
|
254
|
+
const metrics = [];
|
|
255
|
+
if (!fs.existsSync(metricsDir)) {
|
|
256
|
+
return metrics;
|
|
257
|
+
}
|
|
258
|
+
const files = fs.readdirSync(metricsDir).filter(f => f.endsWith(".json")).sort();
|
|
259
|
+
for (const file of files) {
|
|
260
|
+
try {
|
|
261
|
+
const content = fs.readFileSync(path.join(metricsDir, file), "utf-8");
|
|
262
|
+
const data = JSON.parse(content);
|
|
263
|
+
metrics.push(data);
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
// Skip invalid files
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return metrics;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Calculate metrics trend
|
|
273
|
+
*
|
|
274
|
+
* @param metrics - Array of metrics in chronological order
|
|
275
|
+
* @returns Trend information
|
|
276
|
+
*/
|
|
277
|
+
export function calculateMetricsTrend(metrics) {
|
|
278
|
+
if (metrics.length < 2) {
|
|
279
|
+
return { improvement: false, percentChange: 0, description: "Insufficient data for trend" };
|
|
280
|
+
}
|
|
281
|
+
const first = metrics[0];
|
|
282
|
+
const last = metrics[metrics.length - 1];
|
|
283
|
+
const percentChange = last.scorePercentage - first.scorePercentage;
|
|
284
|
+
const improvement = percentChange > 0;
|
|
285
|
+
return {
|
|
286
|
+
improvement,
|
|
287
|
+
percentChange: Math.round(percentChange * 10) / 10,
|
|
288
|
+
description: improvement
|
|
289
|
+
? `Type safety improved by ${percentChange.toFixed(1)}%`
|
|
290
|
+
: `Type safety decreased by ${Math.abs(percentChange).toFixed(1)}%`,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=type-safety-ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-safety-ast.js","sourceRoot":"","sources":["../../src/linters/type-safety-ast.ts"],"names":[],"mappings":"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"}
|