@optave/codegraph 3.5.0 → 3.7.0
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 +47 -21
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/connection.d.ts +12 -2
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +81 -53
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +38 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +69 -3
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +7 -51
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +7 -5
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +2 -2
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +124 -105
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +206 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/dart.d.ts +6 -0
- package/dist/extractors/dart.d.ts.map +1 -0
- package/dist/extractors/dart.js +277 -0
- package/dist/extractors/dart.js.map +1 -0
- package/dist/extractors/elixir.d.ts +9 -0
- package/dist/extractors/elixir.d.ts.map +1 -0
- package/dist/extractors/elixir.js +223 -0
- package/dist/extractors/elixir.js.map +1 -0
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/haskell.d.ts +8 -0
- package/dist/extractors/haskell.d.ts.map +1 -0
- package/dist/extractors/haskell.js +217 -0
- package/dist/extractors/haskell.js.map +1 -0
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +12 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +12 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +306 -292
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/lua.d.ts +6 -0
- package/dist/extractors/lua.d.ts.map +1 -0
- package/dist/extractors/lua.js +162 -0
- package/dist/extractors/lua.js.map +1 -0
- package/dist/extractors/ocaml.d.ts +6 -0
- package/dist/extractors/ocaml.d.ts.map +1 -0
- package/dist/extractors/ocaml.js +236 -0
- package/dist/extractors/ocaml.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -83
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/extractors/zig.d.ts +9 -0
- package/dist/extractors/zig.d.ts.map +1 -0
- package/dist/extractors/zig.js +276 -0
- package/dist/extractors/zig.js.map +1 -0
- package/dist/features/ast.d.ts +2 -0
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +9 -24
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +47 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +72 -61
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +182 -7
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-dart.wasm +0 -0
- package/grammars/tree-sitter-elixir.wasm +0 -0
- package/grammars/tree-sitter-haskell.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-lua.wasm +0 -0
- package/grammars/tree-sitter-ocaml.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-zig.wasm +0 -0
- package/package.json +19 -7
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/connection.ts +90 -59
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +36 -32
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +71 -3
- package/src/domain/graph/builder/stages/build-edges.ts +10 -75
- package/src/domain/graph/builder/stages/build-structure.ts +9 -7
- package/src/domain/graph/builder/stages/collect-files.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
- package/src/domain/graph/builder/stages/finalize.ts +159 -125
- package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +222 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/dart.ts +304 -0
- package/src/extractors/elixir.ts +251 -0
- package/src/extractors/go.ts +152 -134
- package/src/extractors/haskell.ts +235 -0
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +12 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +328 -281
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/lua.ts +169 -0
- package/src/extractors/ocaml.ts +259 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -85
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/extractors/zig.ts +294 -0
- package/src/features/ast.ts +10 -25
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +51 -4
- package/src/features/cfg.ts +113 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +46 -37
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +195 -7
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optave/codegraph",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Local code graph CLI — parse codebases with tree-sitter, build dependency graphs, query them",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -131,12 +131,12 @@
|
|
|
131
131
|
},
|
|
132
132
|
"optionalDependencies": {
|
|
133
133
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
134
|
-
"@optave/codegraph-darwin-arm64": "3.
|
|
135
|
-
"@optave/codegraph-darwin-x64": "3.
|
|
136
|
-
"@optave/codegraph-linux-arm64-gnu": "3.
|
|
137
|
-
"@optave/codegraph-linux-x64-gnu": "3.
|
|
138
|
-
"@optave/codegraph-linux-x64-musl": "3.
|
|
139
|
-
"@optave/codegraph-win32-x64-msvc": "3.
|
|
134
|
+
"@optave/codegraph-darwin-arm64": "3.7.0",
|
|
135
|
+
"@optave/codegraph-darwin-x64": "3.7.0",
|
|
136
|
+
"@optave/codegraph-linux-arm64-gnu": "3.7.0",
|
|
137
|
+
"@optave/codegraph-linux-x64-gnu": "3.7.0",
|
|
138
|
+
"@optave/codegraph-linux-x64-musl": "3.7.0",
|
|
139
|
+
"@optave/codegraph-win32-x64-msvc": "3.7.0"
|
|
140
140
|
},
|
|
141
141
|
"devDependencies": {
|
|
142
142
|
"@biomejs/biome": "^2.4.4",
|
|
@@ -144,19 +144,31 @@
|
|
|
144
144
|
"@commitlint/config-conventional": "^20.0",
|
|
145
145
|
"@huggingface/transformers": "^3.8.1",
|
|
146
146
|
"@tree-sitter-grammars/tree-sitter-hcl": "^1.2.0",
|
|
147
|
+
"@tree-sitter-grammars/tree-sitter-lua": "^0.4.1",
|
|
148
|
+
"@tree-sitter-grammars/tree-sitter-zig": "^1.1.2",
|
|
147
149
|
"@types/better-sqlite3": "^7.6.13",
|
|
148
150
|
"@vitest/coverage-v8": "^4.0.18",
|
|
149
151
|
"commit-and-tag-version": "^12.5",
|
|
150
152
|
"husky": "^9.1",
|
|
153
|
+
"tree-sitter-bash": "^0.25.1",
|
|
154
|
+
"tree-sitter-c": "^0.24.1",
|
|
151
155
|
"tree-sitter-c-sharp": "^0.23.1",
|
|
152
156
|
"tree-sitter-cli": "^0.26.5",
|
|
157
|
+
"tree-sitter-cpp": "^0.23.4",
|
|
158
|
+
"tree-sitter-dart": "^1.0.0",
|
|
159
|
+
"tree-sitter-elixir": "^0.3.5",
|
|
153
160
|
"tree-sitter-go": "^0.25.0",
|
|
161
|
+
"tree-sitter-haskell": "^0.23.1",
|
|
154
162
|
"tree-sitter-java": "^0.23.5",
|
|
155
163
|
"tree-sitter-javascript": "^0.25.0",
|
|
164
|
+
"tree-sitter-kotlin": "^0.3.8",
|
|
165
|
+
"tree-sitter-ocaml": "^0.24.2",
|
|
156
166
|
"tree-sitter-php": "^0.24.2",
|
|
157
167
|
"tree-sitter-python": "^0.25.0",
|
|
158
168
|
"tree-sitter-ruby": "^0.23.1",
|
|
159
169
|
"tree-sitter-rust": "^0.24.0",
|
|
170
|
+
"tree-sitter-scala": "^0.24.0",
|
|
171
|
+
"tree-sitter-swift": "^0.7.1",
|
|
160
172
|
"tree-sitter-typescript": "^0.23.2",
|
|
161
173
|
"typescript": "^6.0.2",
|
|
162
174
|
"vitest": "^4.0.18"
|
|
@@ -102,11 +102,12 @@ async function ensureWasmTreesIfNeeded(
|
|
|
102
102
|
opts: AnalysisOpts,
|
|
103
103
|
rootDir: string,
|
|
104
104
|
): Promise<void> {
|
|
105
|
+
const doAst = opts.ast !== false;
|
|
105
106
|
const doComplexity = opts.complexity !== false;
|
|
106
107
|
const doCfg = opts.cfg !== false;
|
|
107
108
|
const doDataflow = opts.dataflow !== false;
|
|
108
109
|
|
|
109
|
-
if (!doComplexity && !doCfg && !doDataflow) return;
|
|
110
|
+
if (!doAst && !doComplexity && !doCfg && !doDataflow) return;
|
|
110
111
|
|
|
111
112
|
let needsWasmTrees = false;
|
|
112
113
|
for (const [relPath, symbols] of fileSymbols) {
|
|
@@ -131,6 +132,8 @@ async function ensureWasmTreesIfNeeded(
|
|
|
131
132
|
d.endLine > d.line &&
|
|
132
133
|
!d.name.includes('.');
|
|
133
134
|
|
|
135
|
+
// AST: need tree when native didn't provide non-call astNodes
|
|
136
|
+
const needsAst = doAst && !Array.isArray(symbols.astNodes) && WALK_EXTENSIONS.has(ext);
|
|
134
137
|
const needsComplexity =
|
|
135
138
|
doComplexity &&
|
|
136
139
|
COMPLEXITY_EXTENSIONS.has(ext) &&
|
|
@@ -141,7 +144,7 @@ async function ensureWasmTreesIfNeeded(
|
|
|
141
144
|
defs.some((d) => hasFuncBody(d) && d.cfg !== null && !Array.isArray(d.cfg?.blocks));
|
|
142
145
|
const needsDataflow = doDataflow && !symbols.dataflow && DATAFLOW_EXTENSIONS.has(ext);
|
|
143
146
|
|
|
144
|
-
if (needsComplexity || needsCfg || needsDataflow) {
|
|
147
|
+
if (needsAst || needsComplexity || needsCfg || needsDataflow) {
|
|
145
148
|
needsWasmTrees = true;
|
|
146
149
|
break;
|
|
147
150
|
}
|
|
@@ -159,6 +162,80 @@ async function ensureWasmTreesIfNeeded(
|
|
|
159
162
|
|
|
160
163
|
// ─── Per-file visitor setup ─────────────────────────────────────────────
|
|
161
164
|
|
|
165
|
+
/** Check if a definition has a real function body (not a type signature). */
|
|
166
|
+
function hasFuncBody(d: {
|
|
167
|
+
name: string;
|
|
168
|
+
kind: string;
|
|
169
|
+
line: number;
|
|
170
|
+
endLine?: number | null;
|
|
171
|
+
}): boolean {
|
|
172
|
+
return (
|
|
173
|
+
(d.kind === 'function' || d.kind === 'method') &&
|
|
174
|
+
d.line > 0 &&
|
|
175
|
+
d.endLine != null &&
|
|
176
|
+
d.endLine > d.line &&
|
|
177
|
+
!d.name.includes('.')
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Set up AST-store visitor if applicable. */
|
|
182
|
+
function setupAstVisitor(
|
|
183
|
+
db: BetterSqlite3Database,
|
|
184
|
+
relPath: string,
|
|
185
|
+
symbols: ExtractorOutput,
|
|
186
|
+
langId: string,
|
|
187
|
+
ext: string,
|
|
188
|
+
): Visitor | null {
|
|
189
|
+
const astTypeMap = AST_TYPE_MAPS.get(langId);
|
|
190
|
+
if (!astTypeMap || !WALK_EXTENSIONS.has(ext) || Array.isArray(symbols.astNodes)) return null;
|
|
191
|
+
const nodeIdMap = new Map<string, number>();
|
|
192
|
+
for (const row of bulkNodeIdsByFile(db, relPath)) {
|
|
193
|
+
nodeIdMap.set(`${row.name}|${row.kind}|${row.line}`, row.id);
|
|
194
|
+
}
|
|
195
|
+
return createAstStoreVisitor(astTypeMap, symbols.definitions || [], relPath, nodeIdMap);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Set up complexity visitor if any definitions need WASM complexity analysis. */
|
|
199
|
+
function setupComplexityVisitorForFile(
|
|
200
|
+
defs: Definition[],
|
|
201
|
+
langId: string,
|
|
202
|
+
walkerOpts: WalkOptions,
|
|
203
|
+
): Visitor | null {
|
|
204
|
+
const cRules = COMPLEXITY_RULES.get(langId);
|
|
205
|
+
if (!cRules) return null;
|
|
206
|
+
|
|
207
|
+
const hRules = HALSTEAD_RULES.get(langId);
|
|
208
|
+
const needsWasmComplexity = defs.some((d) => hasFuncBody(d) && !d.complexity);
|
|
209
|
+
if (!needsWasmComplexity) return null;
|
|
210
|
+
|
|
211
|
+
const visitor = createComplexityVisitor(cRules, hRules, { fileLevelWalk: true, langId });
|
|
212
|
+
|
|
213
|
+
for (const t of cRules.nestingNodes) walkerOpts.nestingNodeTypes?.add(t);
|
|
214
|
+
|
|
215
|
+
const dfRules = DATAFLOW_RULES.get(langId);
|
|
216
|
+
walkerOpts.getFunctionName = (node: TreeSitterNode): string | null => {
|
|
217
|
+
const nameNode = node.childForFieldName('name');
|
|
218
|
+
if (nameNode) return nameNode.text;
|
|
219
|
+
if (dfRules) return getFuncName(node, dfRules as any);
|
|
220
|
+
return null;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return visitor;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Set up CFG visitor if any definitions need WASM CFG analysis. */
|
|
227
|
+
function setupCfgVisitorForFile(defs: Definition[], langId: string, ext: string): Visitor | null {
|
|
228
|
+
const cfgRulesForLang = CFG_RULES.get(langId);
|
|
229
|
+
if (!cfgRulesForLang || !CFG_EXTENSIONS.has(ext)) return null;
|
|
230
|
+
|
|
231
|
+
const needsWasmCfg = defs.some(
|
|
232
|
+
(d) => hasFuncBody(d) && d.cfg !== null && !Array.isArray(d.cfg?.blocks),
|
|
233
|
+
);
|
|
234
|
+
if (!needsWasmCfg) return null;
|
|
235
|
+
|
|
236
|
+
return createCfgVisitor(cfgRulesForLang);
|
|
237
|
+
}
|
|
238
|
+
|
|
162
239
|
function setupVisitors(
|
|
163
240
|
db: BetterSqlite3Database,
|
|
164
241
|
relPath: string,
|
|
@@ -168,10 +245,6 @@ function setupVisitors(
|
|
|
168
245
|
): SetupResult {
|
|
169
246
|
const ext = path.extname(relPath).toLowerCase();
|
|
170
247
|
const defs = symbols.definitions || [];
|
|
171
|
-
const doAst = opts.ast !== false;
|
|
172
|
-
const doComplexity = opts.complexity !== false;
|
|
173
|
-
const doCfg = opts.cfg !== false;
|
|
174
|
-
const doDataflow = opts.dataflow !== false;
|
|
175
248
|
|
|
176
249
|
const visitors: Visitor[] = [];
|
|
177
250
|
const walkerOpts: WalkOptions = {
|
|
@@ -180,75 +253,19 @@ function setupVisitors(
|
|
|
180
253
|
getFunctionName: (_node: TreeSitterNode) => null,
|
|
181
254
|
};
|
|
182
255
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const astTypeMap = AST_TYPE_MAPS.get(langId);
|
|
186
|
-
if (doAst && astTypeMap && WALK_EXTENSIONS.has(ext) && !Array.isArray(symbols.astNodes)) {
|
|
187
|
-
const nodeIdMap = new Map<string, number>();
|
|
188
|
-
for (const row of bulkNodeIdsByFile(db, relPath)) {
|
|
189
|
-
nodeIdMap.set(`${row.name}|${row.kind}|${row.line}`, row.id);
|
|
190
|
-
}
|
|
191
|
-
astVisitor = createAstStoreVisitor(astTypeMap, defs, relPath, nodeIdMap);
|
|
192
|
-
visitors.push(astVisitor);
|
|
193
|
-
}
|
|
256
|
+
const astVisitor = opts.ast !== false ? setupAstVisitor(db, relPath, symbols, langId, ext) : null;
|
|
257
|
+
if (astVisitor) visitors.push(astVisitor);
|
|
194
258
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const hRules = HALSTEAD_RULES.get(langId);
|
|
199
|
-
if (doComplexity && cRules) {
|
|
200
|
-
// Only trigger WASM complexity for definitions with real function bodies.
|
|
201
|
-
// Interface/type property signatures (dotted names, single-line span)
|
|
202
|
-
// correctly lack native complexity data and should not trigger a fallback.
|
|
203
|
-
const needsWasmComplexity = defs.some(
|
|
204
|
-
(d) =>
|
|
205
|
-
(d.kind === 'function' || d.kind === 'method') &&
|
|
206
|
-
d.line > 0 &&
|
|
207
|
-
d.endLine != null &&
|
|
208
|
-
d.endLine > d.line &&
|
|
209
|
-
!d.name.includes('.') &&
|
|
210
|
-
!d.complexity,
|
|
211
|
-
);
|
|
212
|
-
if (needsWasmComplexity) {
|
|
213
|
-
complexityVisitor = createComplexityVisitor(cRules, hRules, { fileLevelWalk: true, langId });
|
|
214
|
-
visitors.push(complexityVisitor);
|
|
215
|
-
|
|
216
|
-
for (const t of cRules.nestingNodes) walkerOpts.nestingNodeTypes?.add(t);
|
|
217
|
-
|
|
218
|
-
const dfRules = DATAFLOW_RULES.get(langId);
|
|
219
|
-
walkerOpts.getFunctionName = (node: TreeSitterNode): string | null => {
|
|
220
|
-
const nameNode = node.childForFieldName('name');
|
|
221
|
-
if (nameNode) return nameNode.text;
|
|
222
|
-
if (dfRules) return getFuncName(node, dfRules as any);
|
|
223
|
-
return null;
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
}
|
|
259
|
+
const complexityVisitor =
|
|
260
|
+
opts.complexity !== false ? setupComplexityVisitorForFile(defs, langId, walkerOpts) : null;
|
|
261
|
+
if (complexityVisitor) visitors.push(complexityVisitor);
|
|
227
262
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const cfgRulesForLang = CFG_RULES.get(langId);
|
|
231
|
-
if (doCfg && cfgRulesForLang && CFG_EXTENSIONS.has(ext)) {
|
|
232
|
-
const needsWasmCfg = defs.some(
|
|
233
|
-
(d) =>
|
|
234
|
-
(d.kind === 'function' || d.kind === 'method') &&
|
|
235
|
-
d.line > 0 &&
|
|
236
|
-
d.endLine != null &&
|
|
237
|
-
d.endLine > d.line &&
|
|
238
|
-
!d.name.includes('.') &&
|
|
239
|
-
d.cfg !== null &&
|
|
240
|
-
!Array.isArray(d.cfg?.blocks),
|
|
241
|
-
);
|
|
242
|
-
if (needsWasmCfg) {
|
|
243
|
-
cfgVisitor = createCfgVisitor(cfgRulesForLang);
|
|
244
|
-
visitors.push(cfgVisitor);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
263
|
+
const cfgVisitor = opts.cfg !== false ? setupCfgVisitorForFile(defs, langId, ext) : null;
|
|
264
|
+
if (cfgVisitor) visitors.push(cfgVisitor);
|
|
247
265
|
|
|
248
|
-
// Dataflow visitor
|
|
249
266
|
let dataflowVisitor: Visitor | null = null;
|
|
250
267
|
const dfRules = DATAFLOW_RULES.get(langId);
|
|
251
|
-
if (
|
|
268
|
+
if (opts.dataflow !== false && dfRules && DATAFLOW_EXTENSIONS.has(ext) && !symbols.dataflow) {
|
|
252
269
|
dataflowVisitor = createDataflowVisitor(dfRules);
|
|
253
270
|
visitors.push(dataflowVisitor);
|
|
254
271
|
}
|
|
@@ -258,88 +275,80 @@ function setupVisitors(
|
|
|
258
275
|
|
|
259
276
|
// ─── Result storage helpers ─────────────────────────────────────────────
|
|
260
277
|
|
|
261
|
-
function
|
|
262
|
-
|
|
263
|
-
const
|
|
264
|
-
for (const r of
|
|
265
|
-
if (r.funcNode)
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
278
|
+
/** Index per-function results by start line for O(1) lookup. */
|
|
279
|
+
function indexByLine<T extends { funcNode: TreeSitterNode }>(results: T[]): Map<number, T[]> {
|
|
280
|
+
const byLine = new Map<number, T[]>();
|
|
281
|
+
for (const r of results) {
|
|
282
|
+
if (!r.funcNode) continue;
|
|
283
|
+
const line = r.funcNode.startPosition.row + 1;
|
|
284
|
+
if (!byLine.has(line)) byLine.set(line, []);
|
|
285
|
+
byLine.get(line)?.push(r);
|
|
270
286
|
}
|
|
287
|
+
return byLine;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Find the best matching result for a definition by line + name. */
|
|
291
|
+
function matchResultToDef<T extends { funcNode: TreeSitterNode }>(
|
|
292
|
+
candidates: T[] | undefined,
|
|
293
|
+
defName: string,
|
|
294
|
+
): T | undefined {
|
|
295
|
+
if (!candidates) return undefined;
|
|
296
|
+
if (candidates.length === 1) return candidates[0];
|
|
297
|
+
return (
|
|
298
|
+
candidates.find((r) => {
|
|
299
|
+
const n = r.funcNode.childForFieldName('name');
|
|
300
|
+
return n && n.text === defName;
|
|
301
|
+
}) ?? candidates[0]
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function storeComplexityResults(results: WalkResults, defs: Definition[], langId: string): void {
|
|
306
|
+
const byLine = indexByLine((results.complexity || []) as ComplexityFuncResult[]);
|
|
271
307
|
for (const def of defs) {
|
|
272
308
|
if ((def.kind === 'function' || def.kind === 'method') && def.line && !def.complexity) {
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
def.complexity = {
|
|
290
|
-
cognitive: metrics.cognitive,
|
|
291
|
-
cyclomatic: metrics.cyclomatic,
|
|
292
|
-
maxNesting: metrics.maxNesting,
|
|
293
|
-
halstead: metrics.halstead,
|
|
294
|
-
loc,
|
|
295
|
-
maintainabilityIndex: mi,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
309
|
+
const funcResult = matchResultToDef(byLine.get(def.line), def.name);
|
|
310
|
+
if (!funcResult) continue;
|
|
311
|
+
const { metrics } = funcResult;
|
|
312
|
+
const loc = computeLOCMetrics(funcResult.funcNode, langId);
|
|
313
|
+
const volume = metrics.halstead ? metrics.halstead.volume : 0;
|
|
314
|
+
const commentRatio = loc.loc > 0 ? loc.commentLines / loc.loc : 0;
|
|
315
|
+
const mi = computeMaintainabilityIndex(volume, metrics.cyclomatic, loc.sloc, commentRatio);
|
|
316
|
+
def.complexity = {
|
|
317
|
+
cognitive: metrics.cognitive,
|
|
318
|
+
cyclomatic: metrics.cyclomatic,
|
|
319
|
+
maxNesting: metrics.maxNesting,
|
|
320
|
+
halstead: metrics.halstead,
|
|
321
|
+
loc,
|
|
322
|
+
maintainabilityIndex: mi,
|
|
323
|
+
};
|
|
298
324
|
}
|
|
299
325
|
}
|
|
300
326
|
}
|
|
301
327
|
|
|
302
328
|
function storeCfgResults(results: WalkResults, defs: Definition[]): void {
|
|
303
|
-
const
|
|
304
|
-
const cfgByLine = new Map<number, CfgFuncResult[]>();
|
|
305
|
-
for (const r of cfgResults) {
|
|
306
|
-
if (r.funcNode) {
|
|
307
|
-
const line = r.funcNode.startPosition.row + 1;
|
|
308
|
-
if (!cfgByLine.has(line)) cfgByLine.set(line, []);
|
|
309
|
-
cfgByLine.get(line)?.push(r);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
329
|
+
const byLine = indexByLine((results.cfg || []) as CfgFuncResult[]);
|
|
312
330
|
for (const def of defs) {
|
|
313
331
|
if (
|
|
314
332
|
(def.kind === 'function' || def.kind === 'method') &&
|
|
315
333
|
def.line &&
|
|
316
334
|
!def.cfg?.blocks?.length
|
|
317
335
|
) {
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
def.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
const volume = halstead ? halstead.volume : 0;
|
|
335
|
-
const commentRatio = loc && loc.loc > 0 ? loc.commentLines / loc.loc : 0;
|
|
336
|
-
def.complexity.maintainabilityIndex = computeMaintainabilityIndex(
|
|
337
|
-
volume,
|
|
338
|
-
cfgResult.cyclomatic,
|
|
339
|
-
loc?.sloc ?? 0,
|
|
340
|
-
commentRatio,
|
|
341
|
-
);
|
|
342
|
-
}
|
|
336
|
+
const cfgResult = matchResultToDef(byLine.get(def.line), def.name);
|
|
337
|
+
if (!cfgResult) continue;
|
|
338
|
+
def.cfg = { blocks: cfgResult.blocks, edges: cfgResult.edges };
|
|
339
|
+
|
|
340
|
+
// Override complexity's cyclomatic with CFG-derived value (single source of truth)
|
|
341
|
+
if (def.complexity && cfgResult.cyclomatic != null) {
|
|
342
|
+
def.complexity.cyclomatic = cfgResult.cyclomatic;
|
|
343
|
+
const { loc, halstead } = def.complexity;
|
|
344
|
+
const volume = halstead ? halstead.volume : 0;
|
|
345
|
+
const commentRatio = loc && loc.loc > 0 ? loc.commentLines / loc.loc : 0;
|
|
346
|
+
def.complexity.maintainabilityIndex = computeMaintainabilityIndex(
|
|
347
|
+
volume,
|
|
348
|
+
cfgResult.cyclomatic,
|
|
349
|
+
loc?.sloc ?? 0,
|
|
350
|
+
commentRatio,
|
|
351
|
+
);
|
|
343
352
|
}
|
|
344
353
|
}
|
|
345
354
|
}
|
|
@@ -14,7 +14,7 @@ interface AstStoreRow {
|
|
|
14
14
|
kind: string;
|
|
15
15
|
name: string | null | undefined;
|
|
16
16
|
text: string | null;
|
|
17
|
-
receiver: null;
|
|
17
|
+
receiver: string | null;
|
|
18
18
|
parentNodeId: number | null;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -52,6 +52,14 @@ function extractCallName(node: TreeSitterNode): string {
|
|
|
52
52
|
return node.text?.split('(')[0] || '?';
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/** Extract receiver for call expressions (e.g. "obj" in "obj.method()"). */
|
|
56
|
+
function extractCallReceiver(node: TreeSitterNode): string | null {
|
|
57
|
+
const fn = node.childForFieldName('function');
|
|
58
|
+
if (!fn || fn.type !== 'member_expression') return null;
|
|
59
|
+
const obj = fn.childForFieldName('object');
|
|
60
|
+
return obj ? obj.text : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
function extractName(kind: string, node: TreeSitterNode): string | null {
|
|
56
64
|
if (kind === 'throw') {
|
|
57
65
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -161,10 +169,12 @@ export function createAstStoreVisitor(
|
|
|
161
169
|
const line = node.startPosition.row + 1;
|
|
162
170
|
let name: string | null | undefined;
|
|
163
171
|
let text: string | null = null;
|
|
172
|
+
let receiver: string | null = null;
|
|
164
173
|
|
|
165
174
|
if (kind === 'call') {
|
|
166
175
|
name = extractCallName(node);
|
|
167
176
|
text = truncate(node.text);
|
|
177
|
+
receiver = extractCallReceiver(node);
|
|
168
178
|
} else if (kind === 'new') {
|
|
169
179
|
name = extractNewName(node);
|
|
170
180
|
text = truncate(node.text);
|
|
@@ -190,7 +200,7 @@ export function createAstStoreVisitor(
|
|
|
190
200
|
kind,
|
|
191
201
|
name,
|
|
192
202
|
text,
|
|
193
|
-
receiver
|
|
203
|
+
receiver,
|
|
194
204
|
parentNodeId: resolveParentNodeId(line),
|
|
195
205
|
});
|
|
196
206
|
|
|
@@ -201,6 +211,9 @@ export function createAstStoreVisitor(
|
|
|
201
211
|
name: 'ast-store',
|
|
202
212
|
|
|
203
213
|
enterNode(node: TreeSitterNode, _context: VisitorContext): EnterNodeResult | undefined {
|
|
214
|
+
// Guard: skip re-collection but do NOT skipChildren — node.id (memory address)
|
|
215
|
+
// can be reused by tree-sitter, so a collision would incorrectly suppress an
|
|
216
|
+
// unrelated subtree. The parent call's skipChildren handles the intended case.
|
|
204
217
|
if (matched.has(node.id)) return;
|
|
205
218
|
|
|
206
219
|
const kind = astTypeMap[node.type];
|
|
@@ -87,6 +87,16 @@ function classifyBranchNode(
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
function classifyLogicalOp(node: TreeSitterNode, cRules: AnyRules, acc: ComplexityAcc): void {
|
|
91
|
+
const op = node.child(1)?.type;
|
|
92
|
+
if (!op || !cRules.logicalOperators.has(op)) return;
|
|
93
|
+
acc.cyclomatic++;
|
|
94
|
+
const parent = node.parent;
|
|
95
|
+
const sameSequence =
|
|
96
|
+
parent != null && parent.type === cRules.logicalNodeType && parent.child(1)?.type === op;
|
|
97
|
+
if (!sameSequence) acc.cognitive++;
|
|
98
|
+
}
|
|
99
|
+
|
|
90
100
|
function classifyPlainElse(
|
|
91
101
|
node: TreeSitterNode,
|
|
92
102
|
type: string,
|
|
@@ -215,17 +225,7 @@ export function createComplexityVisitor(
|
|
|
215
225
|
if (nestingLevel > acc.maxNesting) acc.maxNesting = nestingLevel;
|
|
216
226
|
|
|
217
227
|
if (type === cRules.logicalNodeType) {
|
|
218
|
-
|
|
219
|
-
if (op && cRules.logicalOperators.has(op)) {
|
|
220
|
-
acc.cyclomatic++;
|
|
221
|
-
const parent = node.parent;
|
|
222
|
-
let sameSequence = false;
|
|
223
|
-
if (parent && parent.type === cRules.logicalNodeType) {
|
|
224
|
-
const parentOp = parent.child(1)?.type;
|
|
225
|
-
if (parentOp === op) sameSequence = true;
|
|
226
|
-
}
|
|
227
|
-
if (!sameSequence) acc.cognitive++;
|
|
228
|
-
}
|
|
228
|
+
classifyLogicalOp(node, cRules, acc);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
if (type === cRules.optionalChainType) acc.cyclomatic++;
|