gitnexus 1.6.6-rc.99 → 1.6.6
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 +122 -68
- package/dist/_shared/graph/types.d.ts +17 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +3 -5
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +2 -4
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +1 -2
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.js +1 -2
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +24 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts +13 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.d.ts +1 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.js +6 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/evidence.d.ts +2 -3
- package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/evidence.js +2 -3
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/macro-registry.d.ts +29 -0
- package/dist/_shared/scope-resolution/registries/macro-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/macro-registry.js +32 -0
- package/dist/_shared/scope-resolution/registries/macro-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts +9 -0
- package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +1 -1
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/ai-context.d.ts +35 -1
- package/dist/cli/ai-context.js +111 -12
- package/dist/cli/analyze-config.d.ts +92 -0
- package/dist/cli/analyze-config.js +364 -0
- package/dist/cli/analyze.d.ts +17 -1
- package/dist/cli/analyze.js +224 -71
- package/dist/cli/cli-message.d.ts +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.js +32 -0
- package/dist/cli/i18n/en.d.ts +2 -2
- package/dist/cli/i18n/en.js +2 -2
- package/dist/cli/i18n/resources.d.ts +2 -2
- package/dist/cli/i18n/zh-CN.js +2 -2
- package/dist/cli/index.js +4 -2
- package/dist/cli/resolve-invocation.d.ts +21 -0
- package/dist/cli/resolve-invocation.js +68 -0
- package/dist/cli/setup.d.ts +33 -0
- package/dist/cli/setup.js +96 -35
- package/dist/cli/skill-gen.js +2 -2
- package/dist/cli/wiki.js +20 -4
- package/dist/core/embeddings/embedder.d.ts +1 -1
- package/dist/core/embeddings/embedder.js +14 -1
- package/dist/core/embeddings/runtime-support.d.ts +41 -0
- package/dist/core/embeddings/runtime-support.js +65 -0
- package/dist/core/group/extractors/grpc-patterns/proto.js +2 -1
- package/dist/core/group/extractors/http-patterns/java.js +15 -1
- package/dist/core/ingestion/call-processor.d.ts +57 -227
- package/dist/core/ingestion/call-processor.js +172 -2595
- package/dist/core/ingestion/call-routing.d.ts +6 -5
- package/dist/core/ingestion/call-routing.js +6 -6
- package/dist/core/ingestion/call-types.d.ts +0 -75
- package/dist/core/ingestion/class-extractors/configs/c-cpp.js +26 -1
- package/dist/core/ingestion/class-extractors/configs/ruby.js +3 -0
- package/dist/core/ingestion/class-extractors/generic.js +9 -11
- package/dist/core/ingestion/class-types.d.ts +23 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.d.ts +11 -0
- package/dist/core/ingestion/cobol/cobol-preprocessor.js +227 -73
- package/dist/core/ingestion/cobol-processor.d.ts +1 -0
- package/dist/core/ingestion/cobol-processor.js +51 -2
- package/dist/core/ingestion/emit-references.js +8 -2
- package/dist/core/ingestion/export-detection.d.ts +2 -1
- package/dist/core/ingestion/export-detection.js +2 -6
- package/dist/core/ingestion/field-extractors/configs/dart.d.ts +0 -6
- package/dist/core/ingestion/field-extractors/configs/dart.js +62 -44
- package/dist/core/ingestion/field-extractors/configs/go.d.ts +0 -9
- package/dist/core/ingestion/field-extractors/configs/go.js +40 -1
- package/dist/core/ingestion/field-extractors/configs/jvm.js +43 -4
- package/dist/core/ingestion/field-extractors/configs/php.js +1 -2
- package/dist/core/ingestion/field-extractors/configs/swift.d.ts +12 -1
- package/dist/core/ingestion/field-extractors/configs/swift.js +31 -6
- package/dist/core/ingestion/field-extractors/generic.d.ts +6 -0
- package/dist/core/ingestion/field-extractors/generic.js +5 -4
- package/dist/core/ingestion/field-extractors/typescript.js +0 -29
- package/dist/core/ingestion/filesystem-walker.d.ts +0 -9
- package/dist/core/ingestion/filesystem-walker.js +0 -11
- package/dist/core/ingestion/finalize-orchestrator.js +14 -2
- package/dist/core/ingestion/import-resolvers/configs/swift.d.ts +21 -0
- package/dist/core/ingestion/import-resolvers/configs/swift.js +72 -11
- package/dist/core/ingestion/import-resolvers/python.d.ts +1 -1
- package/dist/core/ingestion/import-resolvers/standard.d.ts +2 -2
- package/dist/core/ingestion/import-resolvers/standard.js +6 -5
- package/dist/core/ingestion/import-resolvers/utils.d.ts +2 -5
- package/dist/core/ingestion/import-resolvers/utils.js +1 -9
- package/dist/core/ingestion/language-provider.d.ts +39 -119
- package/dist/core/ingestion/language-provider.js +0 -2
- package/dist/core/ingestion/languages/c/capture-side-channel.d.ts +62 -0
- package/dist/core/ingestion/languages/c/capture-side-channel.js +65 -0
- package/dist/core/ingestion/languages/c/captures.js +41 -23
- package/dist/core/ingestion/languages/c/import-decomposer.d.ts +9 -0
- package/dist/core/ingestion/languages/c/import-decomposer.js +15 -0
- package/dist/core/ingestion/languages/c/import-target.js +52 -9
- package/dist/core/ingestion/languages/c/index.d.ts +2 -1
- package/dist/core/ingestion/languages/c/index.js +2 -1
- package/dist/core/ingestion/languages/c/query.js +15 -0
- package/dist/core/ingestion/languages/c/scope-resolver.js +47 -4
- package/dist/core/ingestion/languages/c/static-linkage.d.ts +8 -0
- package/dist/core/ingestion/languages/c/static-linkage.js +46 -1
- package/dist/core/ingestion/languages/c-cpp.js +16 -7
- package/dist/core/ingestion/languages/cobol/captures.js +25 -2
- package/dist/core/ingestion/languages/cpp/adl.d.ts +88 -4
- package/dist/core/ingestion/languages/cpp/adl.js +380 -160
- package/dist/core/ingestion/languages/cpp/arity-metadata.js +2 -8
- package/dist/core/ingestion/languages/cpp/capture-side-channel.d.ts +65 -0
- package/dist/core/ingestion/languages/cpp/capture-side-channel.js +78 -0
- package/dist/core/ingestion/languages/cpp/captures.js +162 -54
- package/dist/core/ingestion/languages/cpp/file-local-linkage.d.ts +18 -52
- package/dist/core/ingestion/languages/cpp/file-local-linkage.js +49 -1
- package/dist/core/ingestion/languages/cpp/import-decomposer.d.ts +7 -0
- package/dist/core/ingestion/languages/cpp/import-decomposer.js +12 -0
- package/dist/core/ingestion/languages/cpp/index.d.ts +1 -0
- package/dist/core/ingestion/languages/cpp/index.js +1 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.d.ts +8 -0
- package/dist/core/ingestion/languages/cpp/inline-namespaces.js +21 -0
- package/dist/core/ingestion/languages/cpp/query.js +21 -0
- package/dist/core/ingestion/languages/cpp/range-bindings.js +20 -5
- package/dist/core/ingestion/languages/cpp/scope-resolver.js +52 -5
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.d.ts +20 -0
- package/dist/core/ingestion/languages/cpp/two-phase-lookup.js +83 -3
- package/dist/core/ingestion/languages/csharp/captures.js +205 -41
- package/dist/core/ingestion/languages/csharp/index.d.ts +3 -4
- package/dist/core/ingestion/languages/csharp/index.js +3 -4
- package/dist/core/ingestion/languages/csharp/interpret.js +17 -3
- package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +17 -7
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +129 -124
- package/dist/core/ingestion/languages/csharp/qualified-type-names.d.ts +14 -0
- package/dist/core/ingestion/languages/csharp/qualified-type-names.js +59 -0
- package/dist/core/ingestion/languages/csharp/query.js +13 -0
- package/dist/core/ingestion/languages/csharp/receiver-binding.js +10 -6
- package/dist/core/ingestion/languages/csharp/scope-resolver.js +8 -1
- package/dist/core/ingestion/languages/csharp.js +0 -5
- package/dist/core/ingestion/languages/dart/arity-metadata.d.ts +25 -0
- package/dist/core/ingestion/languages/dart/arity-metadata.js +35 -0
- package/dist/core/ingestion/languages/dart/arity.d.ts +19 -0
- package/dist/core/ingestion/languages/dart/arity.js +31 -0
- package/dist/core/ingestion/languages/dart/built-ins.d.ts +11 -0
- package/dist/core/ingestion/languages/dart/built-ins.js +34 -0
- package/dist/core/ingestion/languages/dart/cache-stats.d.ts +13 -0
- package/dist/core/ingestion/languages/dart/cache-stats.js +24 -0
- package/dist/core/ingestion/languages/dart/captures.d.ts +29 -0
- package/dist/core/ingestion/languages/dart/captures.js +445 -0
- package/dist/core/ingestion/languages/dart/expand-wildcards.d.ts +13 -0
- package/dist/core/ingestion/languages/dart/expand-wildcards.js +31 -0
- package/dist/core/ingestion/languages/dart/import-target.d.ts +15 -0
- package/dist/core/ingestion/languages/dart/import-target.js +65 -0
- package/dist/core/ingestion/languages/dart/index.d.ts +28 -0
- package/dist/core/ingestion/languages/dart/index.js +28 -0
- package/dist/core/ingestion/languages/dart/interpret.d.ts +24 -0
- package/dist/core/ingestion/languages/dart/interpret.js +95 -0
- package/dist/core/ingestion/languages/dart/merge-bindings.d.ts +10 -0
- package/dist/core/ingestion/languages/dart/merge-bindings.js +39 -0
- package/dist/core/ingestion/languages/dart/query.d.ts +26 -0
- package/dist/core/ingestion/languages/dart/query.js +142 -0
- package/dist/core/ingestion/languages/dart/receiver-binding.d.ts +24 -0
- package/dist/core/ingestion/languages/dart/receiver-binding.js +87 -0
- package/dist/core/ingestion/languages/dart/scope-resolver.d.ts +29 -0
- package/dist/core/ingestion/languages/dart/scope-resolver.js +194 -0
- package/dist/core/ingestion/languages/dart/signature-bindings.d.ts +23 -0
- package/dist/core/ingestion/languages/dart/signature-bindings.js +51 -0
- package/dist/core/ingestion/languages/dart/simple-hooks.d.ts +20 -0
- package/dist/core/ingestion/languages/dart/simple-hooks.js +47 -0
- package/dist/core/ingestion/languages/dart.d.ts +0 -1
- package/dist/core/ingestion/languages/dart.js +15 -29
- package/dist/core/ingestion/languages/go/arity-metadata.d.ts +1 -0
- package/dist/core/ingestion/languages/go/arity-metadata.js +31 -1
- package/dist/core/ingestion/languages/go/captures.js +162 -3
- package/dist/core/ingestion/languages/go/interface-impls.js +476 -50
- package/dist/core/ingestion/languages/go/interpret.js +21 -11
- package/dist/core/ingestion/languages/go/method-owners.js +20 -8
- package/dist/core/ingestion/languages/go/query.js +15 -7
- package/dist/core/ingestion/languages/go/range-binding.js +24 -9
- package/dist/core/ingestion/languages/go/receiver-binding.js +1 -1
- package/dist/core/ingestion/languages/go/scope-resolver.js +2 -2
- package/dist/core/ingestion/languages/go/simple-hooks.js +10 -5
- package/dist/core/ingestion/languages/go/type-binding.d.ts +1 -0
- package/dist/core/ingestion/languages/go/type-binding.js +40 -2
- package/dist/core/ingestion/languages/go.d.ts +0 -1
- package/dist/core/ingestion/languages/go.js +0 -5
- package/dist/core/ingestion/languages/index.d.ts +0 -5
- package/dist/core/ingestion/languages/index.js +0 -3
- package/dist/core/ingestion/languages/java/captures.js +252 -23
- package/dist/core/ingestion/languages/java/interpret.js +12 -6
- package/dist/core/ingestion/languages/java/package-siblings.js +18 -5
- package/dist/core/ingestion/languages/java/query.js +16 -1
- package/dist/core/ingestion/languages/java/scope-resolver.d.ts +2 -8
- package/dist/core/ingestion/languages/java/scope-resolver.js +2 -8
- package/dist/core/ingestion/languages/java.js +0 -5
- package/dist/core/ingestion/languages/javascript/captures.js +185 -11
- package/dist/core/ingestion/languages/javascript/query.js +107 -1
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +57 -0
- package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +60 -0
- package/dist/core/ingestion/languages/kotlin/captures.js +213 -22
- package/dist/core/ingestion/languages/kotlin/companion-scopes.d.ts +7 -0
- package/dist/core/ingestion/languages/kotlin/companion-scopes.js +10 -0
- package/dist/core/ingestion/languages/kotlin/index.d.ts +1 -0
- package/dist/core/ingestion/languages/kotlin/index.js +1 -0
- package/dist/core/ingestion/languages/kotlin/query.js +30 -0
- package/dist/core/ingestion/languages/kotlin/scope-resolver.d.ts +5 -7
- package/dist/core/ingestion/languages/kotlin/scope-resolver.js +22 -7
- package/dist/core/ingestion/languages/kotlin.js +8 -5
- package/dist/core/ingestion/languages/php/captures.js +135 -19
- package/dist/core/ingestion/languages/php/import-decomposer.js +21 -63
- package/dist/core/ingestion/languages/php/index.d.ts +3 -4
- package/dist/core/ingestion/languages/php/index.js +3 -4
- package/dist/core/ingestion/languages/php/query.js +5 -0
- package/dist/core/ingestion/languages/php/receiver-binding.js +8 -4
- package/dist/core/ingestion/languages/php.js +0 -4
- package/dist/core/ingestion/languages/python/captures.js +128 -13
- package/dist/core/ingestion/languages/python/depends-references.js +1 -1
- package/dist/core/ingestion/languages/python/import-target.d.ts +4 -5
- package/dist/core/ingestion/languages/python/import-target.js +108 -16
- package/dist/core/ingestion/languages/python/index-stats.d.ts +18 -0
- package/dist/core/ingestion/languages/python/index-stats.js +25 -0
- package/dist/core/ingestion/languages/python/index.d.ts +3 -4
- package/dist/core/ingestion/languages/python/index.js +3 -4
- package/dist/core/ingestion/languages/python/query.js +17 -0
- package/dist/core/ingestion/languages/python/scope-resolver.js +7 -6
- package/dist/core/ingestion/languages/python.d.ts +0 -2
- package/dist/core/ingestion/languages/python.js +0 -7
- package/dist/core/ingestion/languages/ruby/captures.js +174 -31
- package/dist/core/ingestion/languages/ruby/import-target.js +2 -1
- package/dist/core/ingestion/languages/ruby/interpret.js +2 -1
- package/dist/core/ingestion/languages/ruby/query.js +10 -0
- package/dist/core/ingestion/languages/ruby/scope-resolver.js +61 -11
- package/dist/core/ingestion/languages/ruby.js +4 -53
- package/dist/core/ingestion/languages/rust/captures.js +95 -13
- package/dist/core/ingestion/languages/rust/query.js +64 -1
- package/dist/core/ingestion/languages/rust/range-binding.js +40 -12
- package/dist/core/ingestion/languages/rust/receiver-binding.js +9 -0
- package/dist/core/ingestion/languages/rust/scope-resolver.js +75 -1
- package/dist/core/ingestion/languages/rust.d.ts +0 -2
- package/dist/core/ingestion/languages/rust.js +0 -6
- package/dist/core/ingestion/languages/swift/arity-metadata.d.ts +24 -0
- package/dist/core/ingestion/languages/swift/arity-metadata.js +41 -0
- package/dist/core/ingestion/languages/swift/arity.d.ts +29 -0
- package/dist/core/ingestion/languages/swift/arity.js +42 -0
- package/dist/core/ingestion/languages/swift/base-type.d.ts +20 -0
- package/dist/core/ingestion/languages/swift/base-type.js +27 -0
- package/dist/core/ingestion/languages/swift/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/swift/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/swift/captures.d.ts +35 -0
- package/dist/core/ingestion/languages/swift/captures.js +495 -0
- package/dist/core/ingestion/languages/swift/implicit-imports.d.ts +34 -0
- package/dist/core/ingestion/languages/swift/implicit-imports.js +57 -0
- package/dist/core/ingestion/languages/swift/import-decomposer.d.ts +24 -0
- package/dist/core/ingestion/languages/swift/import-decomposer.js +84 -0
- package/dist/core/ingestion/languages/swift/import-target.d.ts +33 -0
- package/dist/core/ingestion/languages/swift/import-target.js +81 -0
- package/dist/core/ingestion/languages/swift/index.d.ts +37 -0
- package/dist/core/ingestion/languages/swift/index.js +37 -0
- package/dist/core/ingestion/languages/swift/interpret.d.ts +15 -0
- package/dist/core/ingestion/languages/swift/interpret.js +89 -0
- package/dist/core/ingestion/languages/swift/merge-bindings.d.ts +20 -0
- package/dist/core/ingestion/languages/swift/merge-bindings.js +48 -0
- package/dist/core/ingestion/languages/swift/query.d.ts +46 -0
- package/dist/core/ingestion/languages/swift/query.js +194 -0
- package/dist/core/ingestion/languages/swift/receiver-binding.d.ts +40 -0
- package/dist/core/ingestion/languages/swift/receiver-binding.js +161 -0
- package/dist/core/ingestion/languages/swift/scope-resolver.d.ts +50 -0
- package/dist/core/ingestion/languages/swift/scope-resolver.js +189 -0
- package/dist/core/ingestion/languages/swift/sibling-type-bindings.d.ts +34 -0
- package/dist/core/ingestion/languages/swift/sibling-type-bindings.js +65 -0
- package/dist/core/ingestion/languages/swift/signature-bindings.d.ts +25 -0
- package/dist/core/ingestion/languages/swift/signature-bindings.js +66 -0
- package/dist/core/ingestion/languages/swift/simple-hooks.d.ts +37 -0
- package/dist/core/ingestion/languages/swift/simple-hooks.js +60 -0
- package/dist/core/ingestion/languages/swift/target-grouping.d.ts +51 -0
- package/dist/core/ingestion/languages/swift/target-grouping.js +93 -0
- package/dist/core/ingestion/languages/swift/target-siblings.d.ts +30 -0
- package/dist/core/ingestion/languages/swift/target-siblings.js +71 -0
- package/dist/core/ingestion/languages/swift.d.ts +0 -5
- package/dist/core/ingestion/languages/swift.js +11 -87
- package/dist/core/ingestion/languages/typescript/array-callback.d.ts +3 -29
- package/dist/core/ingestion/languages/typescript/array-callback.js +4 -43
- package/dist/core/ingestion/languages/typescript/captures.js +147 -17
- package/dist/core/ingestion/languages/typescript/index.d.ts +3 -4
- package/dist/core/ingestion/languages/typescript/index.js +3 -4
- package/dist/core/ingestion/languages/typescript/query.d.ts +2 -3
- package/dist/core/ingestion/languages/typescript/query.js +125 -4
- package/dist/core/ingestion/languages/typescript/receiver-binding.js +0 -1
- package/dist/core/ingestion/languages/typescript.d.ts +2 -3
- package/dist/core/ingestion/languages/typescript.js +46 -23
- package/dist/core/ingestion/languages/vue/captures.d.ts +46 -0
- package/dist/core/ingestion/languages/vue/captures.js +67 -0
- package/dist/core/ingestion/languages/vue/import-target.d.ts +27 -0
- package/dist/core/ingestion/languages/vue/import-target.js +58 -0
- package/dist/core/ingestion/languages/vue/index.d.ts +49 -0
- package/dist/core/ingestion/languages/vue/index.js +49 -0
- package/dist/core/ingestion/languages/vue/scope-resolver.d.ts +55 -0
- package/dist/core/ingestion/languages/vue/scope-resolver.js +292 -0
- package/dist/core/ingestion/languages/vue.js +12 -4
- package/dist/core/ingestion/local-symbol-pruner.d.ts +11 -0
- package/dist/core/ingestion/local-symbol-pruner.js +63 -0
- package/dist/core/ingestion/method-extractors/configs/dart.js +14 -1
- package/dist/core/ingestion/method-extractors/configs/jvm.js +37 -20
- package/dist/core/ingestion/method-extractors/configs/php.js +0 -1
- package/dist/core/ingestion/method-extractors/configs/swift.js +11 -4
- package/dist/core/ingestion/method-types.d.ts +2 -2
- package/dist/core/ingestion/model/index.d.ts +0 -3
- package/dist/core/ingestion/model/index.js +0 -8
- package/dist/core/ingestion/model/resolve.d.ts +7 -43
- package/dist/core/ingestion/model/resolve.js +7 -226
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +46 -1
- package/dist/core/ingestion/model/semantic-model.d.ts +4 -6
- package/dist/core/ingestion/model/semantic-model.js +1 -1
- package/dist/core/ingestion/model/symbol-table.d.ts +3 -4
- package/dist/core/ingestion/model/symbol-table.js +3 -4
- package/dist/core/ingestion/parsing-processor.d.ts +30 -24
- package/dist/core/ingestion/parsing-processor.js +76 -640
- package/dist/core/ingestion/pipeline-phases/communities.d.ts +1 -1
- package/dist/core/ingestion/pipeline-phases/communities.js +5 -2
- package/dist/core/ingestion/pipeline-phases/cross-file.d.ts +9 -8
- package/dist/core/ingestion/pipeline-phases/cross-file.js +16 -12
- package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/index.js +1 -0
- package/dist/core/ingestion/pipeline-phases/mro.d.ts +1 -1
- package/dist/core/ingestion/pipeline-phases/mro.js +2 -2
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +44 -22
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +426 -565
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +13 -33
- package/dist/core/ingestion/pipeline-phases/parse.js +2 -2
- package/dist/core/ingestion/pipeline-phases/processes.d.ts +1 -1
- package/dist/core/ingestion/pipeline-phases/processes.js +5 -3
- package/dist/core/ingestion/pipeline-phases/prune-local-symbols.d.ts +14 -0
- package/dist/core/ingestion/pipeline-phases/prune-local-symbols.js +26 -0
- package/dist/core/ingestion/pipeline.d.ts +27 -19
- package/dist/core/ingestion/pipeline.js +4 -2
- package/dist/core/ingestion/resolve-references.js +15 -3
- package/dist/core/ingestion/route-extractors/laravel.d.ts +10 -0
- package/dist/core/ingestion/route-extractors/laravel.js +88 -9
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +2 -1
- package/dist/core/ingestion/scope-extractor-bridge.js +2 -2
- package/dist/core/ingestion/scope-extractor.js +13 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +181 -15
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +21 -10
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +10 -2
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +7 -1
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +58 -6
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +24 -5
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +68 -1
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +189 -29
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +21 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +1 -1
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +8 -11
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +171 -50
- package/dist/core/ingestion/scope-resolution/pipeline/registry.d.ts +3 -4
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +9 -4
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +28 -5
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +191 -24
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +31 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +72 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +440 -39
- package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +18 -2
- package/dist/core/ingestion/scope-resolution/workspace-index.js +94 -7
- package/dist/core/ingestion/tree-sitter-queries.d.ts +14 -14
- package/dist/core/ingestion/tree-sitter-queries.js +380 -158
- package/dist/core/ingestion/ts-js-hoc-utils.d.ts +12 -0
- package/dist/core/ingestion/ts-js-hoc-utils.js +105 -0
- package/dist/core/ingestion/type-env.d.ts +2 -1
- package/dist/core/ingestion/type-env.js +6 -8
- package/dist/core/ingestion/type-extractors/c-cpp.js +8 -10
- package/dist/core/ingestion/type-extractors/csharp.js +18 -34
- package/dist/core/ingestion/type-extractors/go.js +2 -10
- package/dist/core/ingestion/type-extractors/jvm.js +6 -5
- package/dist/core/ingestion/type-extractors/php.js +1 -1
- package/dist/core/ingestion/type-extractors/python.js +1 -1
- package/dist/core/ingestion/type-extractors/ruby.js +2 -2
- package/dist/core/ingestion/type-extractors/rust.js +0 -16
- package/dist/core/ingestion/type-extractors/shared.d.ts +2 -2
- package/dist/core/ingestion/type-extractors/shared.js +25 -11
- package/dist/core/ingestion/type-extractors/swift.js +5 -5
- package/dist/core/ingestion/type-extractors/types.d.ts +1 -1
- package/dist/core/ingestion/type-extractors/typescript.js +1 -1
- package/dist/core/ingestion/utils/ast-helpers.d.ts +119 -1
- package/dist/core/ingestion/utils/ast-helpers.js +260 -13
- package/dist/core/ingestion/utils/callable-labels.d.ts +13 -0
- package/dist/core/ingestion/utils/callable-labels.js +14 -0
- package/dist/core/ingestion/utils/deferred-resolution-profile.d.ts +10 -0
- package/dist/core/ingestion/utils/deferred-resolution-profile.js +30 -0
- package/dist/core/ingestion/utils/heap-probe.d.ts +20 -0
- package/dist/core/ingestion/utils/heap-probe.js +39 -0
- package/dist/core/ingestion/utils/heritage-marker.d.ts +33 -0
- package/dist/core/ingestion/utils/heritage-marker.js +41 -0
- package/dist/core/ingestion/utils/qualified-name.d.ts +37 -0
- package/dist/core/ingestion/utils/qualified-name.js +67 -0
- package/dist/core/ingestion/variable-extractors/configs/c-cpp.js +49 -0
- package/dist/core/ingestion/variable-extractors/configs/dart.js +76 -62
- package/dist/core/ingestion/variable-extractors/configs/go.js +74 -7
- package/dist/core/ingestion/variable-extractors/configs/jvm.js +35 -8
- package/dist/core/ingestion/variable-extractors/generic.js +40 -12
- package/dist/core/ingestion/variable-types.d.ts +9 -0
- package/dist/core/ingestion/vue-sfc-extractor.d.ts +97 -7
- package/dist/core/ingestion/vue-sfc-extractor.js +433 -11
- package/dist/core/ingestion/workers/parse-worker.d.ts +0 -11
- package/dist/core/ingestion/workers/parse-worker.js +358 -187
- package/dist/core/ingestion/workers/worker-pool.d.ts +78 -9
- package/dist/core/ingestion/workers/worker-pool.js +346 -49
- package/dist/core/lbug/csv-generator.js +20 -2
- package/dist/core/lbug/lbug-adapter.js +29 -10
- package/dist/core/lbug/native-check.js +17 -5
- package/dist/core/lbug/pool-adapter.d.ts +0 -19
- package/dist/core/lbug/pool-adapter.js +40 -77
- package/dist/core/lbug/query-result-utils.d.ts +19 -0
- package/dist/core/lbug/query-result-utils.js +28 -0
- package/dist/core/run-analyze.d.ts +9 -2
- package/dist/core/run-analyze.js +24 -3
- package/dist/core/tree-sitter/parser-loader.d.ts +13 -0
- package/dist/core/tree-sitter/parser-loader.js +4 -0
- package/dist/core/tree-sitter/safe-parse.d.ts +70 -3
- package/dist/core/tree-sitter/safe-parse.js +214 -11
- package/dist/core/wiki/generator.js +13 -5
- package/dist/core/wiki/graph-queries.d.ts +3 -0
- package/dist/core/wiki/graph-queries.js +9 -1
- package/dist/core/wiki/llm-client.d.ts +1 -1
- package/dist/core/wiki/llm-client.js +7 -2
- package/dist/core/wiki/local-cli-client.d.ts +2 -1
- package/dist/core/wiki/local-cli-client.js +62 -4
- package/dist/mcp/compatible-stdio-transport.d.ts +3 -0
- package/dist/mcp/compatible-stdio-transport.js +22 -0
- package/dist/mcp/core/embedder.d.ts +1 -1
- package/dist/mcp/core/embedder.js +13 -1
- package/dist/mcp/local/local-backend.d.ts +37 -5
- package/dist/mcp/local/local-backend.js +227 -129
- package/dist/mcp/resources.js +3 -3
- package/dist/mcp/server.js +9 -1
- package/dist/storage/git.d.ts +11 -0
- package/dist/storage/git.js +30 -0
- package/dist/storage/parse-cache.d.ts +23 -1
- package/dist/storage/parse-cache.js +138 -32
- package/dist/storage/parsedfile-store.d.ts +142 -0
- package/dist/storage/parsedfile-store.js +367 -0
- package/dist/storage/repo-manager.d.ts +2 -1
- package/dist/storage/scope-index-store.d.ts +114 -0
- package/dist/storage/scope-index-store.js +236 -0
- package/dist/types/pipeline.d.ts +6 -3
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +2 -1
- package/hooks/claude/gitnexus-hook.cjs +2 -1
- package/hooks/claude/resolve-analyze-cmd.cjs +323 -0
- package/package.json +4 -5
- package/scripts/bench-scope-resolution.ts +1 -3
- package/scripts/cross-platform-tests.ts +4 -1
- package/skills/gitnexus-cli.md +8 -6
- package/skills/gitnexus-debugging.md +15 -15
- package/skills/gitnexus-exploring.md +11 -11
- package/skills/gitnexus-guide.md +1 -1
- package/skills/gitnexus-impact-analysis.md +10 -10
- package/skills/gitnexus-pr-review.md +19 -19
- package/skills/gitnexus-refactoring.md +25 -25
- package/web/assets/{agent-BRX-afm3.js → agent-EkX7webX.js} +156 -131
- package/web/assets/{architectureDiagram-UL44E2DR-B1oYB8-c.js → architectureDiagram-UL44E2DR-BoczH8cv.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-SPC6pgWI.js → chunk-LCXTWHL2-By5HB3b-.js} +1 -1
- package/web/assets/{chunk-RG4AUYOV-DZXr4Yv3.js → chunk-RG4AUYOV-BQE_DkpL.js} +1 -1
- package/web/assets/{classDiagram-KGZ6W3CR-BqpOj8L9.js → classDiagram-KGZ6W3CR-Dj_02GUH.js} +1 -1
- package/web/assets/{classDiagram-v2-72OJOZXJ-FmElywK2.js → classDiagram-v2-72OJOZXJ-D-NArMpf.js} +1 -1
- package/web/assets/{diagram-3NCE3AQN-BWtJXMDq.js → diagram-3NCE3AQN-VXtXDO95.js} +1 -1
- package/web/assets/{diagram-GF46GFSD-Hh-fChxU.js → diagram-GF46GFSD-B1qab2Ah.js} +1 -1
- package/web/assets/{diagram-QXG6HAR7-DYeQHxGU.js → diagram-QXG6HAR7-BSCHGzzT.js} +1 -1
- package/web/assets/{diagram-WEQXMOUZ-DYGU4T0y.js → diagram-WEQXMOUZ-DHtknmNT.js} +1 -1
- package/web/assets/{erDiagram-L5TCEMPS-bN3wlP2A.js → erDiagram-L5TCEMPS-Db-IYTmm.js} +1 -1
- package/web/assets/{flowDiagram-H6V6AXG4-YACVtF3-.js → flowDiagram-H6V6AXG4-BHDoyVoW.js} +1 -1
- package/web/assets/{index-BhnAdWTt.js → index-BR0IhgbR.js} +10 -10
- package/web/assets/{infoDiagram-3YFTVSEB-BWBzD28-.js → infoDiagram-3YFTVSEB-6h8wbWEe.js} +1 -1
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-B8qYT-j9.js → ishikawaDiagram-BNXS4ZKH-Dx2OkPk1.js} +1 -1
- package/web/assets/{kanban-definition-75IXJCU3-BeoPr5Tl.js → kanban-definition-75IXJCU3-CIIEZfqV.js} +1 -1
- package/web/assets/{mindmap-definition-2TDM6QVE-CdLLN_so.js → mindmap-definition-2TDM6QVE-DUAqydRq.js} +1 -1
- package/web/assets/{pieDiagram-CU6KROY3-DEd2a_k_.js → pieDiagram-CU6KROY3-BntYuYZa.js} +1 -1
- package/web/assets/{requirementDiagram-JXO7QTGE-QNeTo5C_.js → requirementDiagram-JXO7QTGE-QCD6I29n.js} +1 -1
- package/web/assets/{sequenceDiagram-VS2MUI6T-BHC7q7yJ.js → sequenceDiagram-VS2MUI6T-DScFwLz2.js} +1 -1
- package/web/assets/{stateDiagram-7D4R322I-KONnc2Px.js → stateDiagram-7D4R322I-AkRAm6Hl.js} +1 -1
- package/web/assets/{stateDiagram-v2-36443NZ5-C2QfuMlu.js → stateDiagram-v2-36443NZ5-BCK1vigR.js} +1 -1
- package/web/assets/{timeline-definition-O6YCAMPW-D4t4NJx1.js → timeline-definition-O6YCAMPW-BvpIVXjX.js} +1 -1
- package/web/assets/{vennDiagram-MWXL3ELB-6bctC9Yg.js → vennDiagram-MWXL3ELB-BYGWk6dK.js} +1 -1
- package/web/assets/{wardleyDiagram-CUQ6CDDI-BPZYNTvC.js → wardleyDiagram-CUQ6CDDI-Dk1z7H2T.js} +1 -1
- package/web/assets/{xychartDiagram-N2JHSOCM-lBI9O6DW.js → xychartDiagram-N2JHSOCM-2N6NCSWN.js} +1 -1
- package/web/index.html +1 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +0 -63
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +0 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.js +0 -122
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +0 -1
- package/dist/_shared/scope-resolution/shadow/diff.d.ts +0 -59
- package/dist/_shared/scope-resolution/shadow/diff.d.ts.map +0 -1
- package/dist/_shared/scope-resolution/shadow/diff.js +0 -79
- package/dist/_shared/scope-resolution/shadow/diff.js.map +0 -1
- package/dist/core/ingestion/ast-cache.d.ts +0 -26
- package/dist/core/ingestion/ast-cache.js +0 -48
- package/dist/core/ingestion/heritage-extractors/configs/go.d.ts +0 -13
- package/dist/core/ingestion/heritage-extractors/configs/go.js +0 -20
- package/dist/core/ingestion/heritage-extractors/configs/ruby.d.ts +0 -18
- package/dist/core/ingestion/heritage-extractors/configs/ruby.js +0 -65
- package/dist/core/ingestion/heritage-extractors/generic.d.ts +0 -23
- package/dist/core/ingestion/heritage-extractors/generic.js +0 -47
- package/dist/core/ingestion/heritage-processor.d.ts +0 -54
- package/dist/core/ingestion/heritage-processor.js +0 -367
- package/dist/core/ingestion/heritage-types.d.ts +0 -73
- package/dist/core/ingestion/heritage-types.js +0 -2
- package/dist/core/ingestion/import-processor.d.ts +0 -23
- package/dist/core/ingestion/import-processor.js +0 -377
- package/dist/core/ingestion/model/heritage-map.d.ts +0 -105
- package/dist/core/ingestion/model/heritage-map.js +0 -294
- package/dist/core/ingestion/model/resolution-context.d.ts +0 -93
- package/dist/core/ingestion/model/resolution-context.js +0 -337
- package/dist/core/ingestion/named-bindings/csharp.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/csharp.js +0 -37
- package/dist/core/ingestion/named-bindings/java.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/java.js +0 -29
- package/dist/core/ingestion/named-bindings/kotlin.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/kotlin.js +0 -36
- package/dist/core/ingestion/named-bindings/php.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/php.js +0 -61
- package/dist/core/ingestion/named-bindings/python.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/python.js +0 -49
- package/dist/core/ingestion/named-bindings/rust.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/rust.js +0 -66
- package/dist/core/ingestion/named-bindings/types.d.ts +0 -16
- package/dist/core/ingestion/named-bindings/types.js +0 -6
- package/dist/core/ingestion/named-bindings/typescript.d.ts +0 -3
- package/dist/core/ingestion/named-bindings/typescript.js +0 -58
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.d.ts +0 -17
- package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +0 -209
- package/dist/core/ingestion/pipeline-phases/orm-extraction.d.ts +0 -22
- package/dist/core/ingestion/pipeline-phases/orm-extraction.js +0 -92
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.d.ts +0 -70
- package/dist/core/ingestion/pipeline-phases/wildcard-synthesis.js +0 -312
- package/dist/core/ingestion/registry-primary-flag.d.ts +0 -89
- package/dist/core/ingestion/registry-primary-flag.js +0 -122
- package/dist/core/ingestion/shadow-harness.d.ts +0 -113
- package/dist/core/ingestion/shadow-harness.js +0 -148
- package/dist/core/ingestion/utils/ruby-self-call.d.ts +0 -52
- package/dist/core/ingestion/utils/ruby-self-call.js +0 -59
- package/scripts/ci-list-migrated-languages.ts +0 -24
- package/scripts/run-parity.ts +0 -128
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findChild, nodeIfType, nodeToCapture, syntheticCapture, walkNamedTree, } from '../../utils/ast-helpers.js';
|
|
2
2
|
import { getRubyParser, getRubyScopeQuery } from './query.js';
|
|
3
3
|
import { recordRubyCacheHit, recordRubyCacheMiss } from './cache-stats.js';
|
|
4
4
|
import { synthesizeRubyReceiverBinding, findEnclosingClassOrModule } from './receiver-binding.js';
|
|
5
5
|
import { getTreeSitterBufferSize } from '../../constants.js';
|
|
6
6
|
import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
|
|
7
|
+
import { splitQualifiedName } from '../../utils/qualified-name.js';
|
|
8
|
+
import { encodeMarker } from '../../utils/heritage-marker.js';
|
|
7
9
|
const FUNCTION_NODE_TYPES = ['method', 'singleton_method'];
|
|
8
10
|
const HERITAGE_CALL_NAMES = new Set(['include', 'extend', 'prepend']);
|
|
9
11
|
const ATTR_CALL_NAMES = new Set([
|
|
@@ -11,6 +13,35 @@ const ATTR_CALL_NAMES = new Set([
|
|
|
11
13
|
'attr_reader',
|
|
12
14
|
'attr_writer',
|
|
13
15
|
]);
|
|
16
|
+
/**
|
|
17
|
+
* Build the full `.`-joined qualified owner name for a heritage/attr call by
|
|
18
|
+
* walking ALL enclosing class/module ancestors (not just the immediate one),
|
|
19
|
+
* so a same-tail nested owner (`module Outer; class Inner`) is keyed by its
|
|
20
|
+
* full path `Outer.Inner` instead of the bare tail `Inner` — which otherwise
|
|
21
|
+
* collapses both same-tail owners onto one `__heritage__`/`__property__` marker
|
|
22
|
+
* key (last-wins) and cross-wires their mixin / attr_accessor edges (#1982).
|
|
23
|
+
* Handles the compact `class Outer::Inner` form (name is a `scope_resolution`)
|
|
24
|
+
* via the shared normalizer, so the marker owner byte-matches the resolution
|
|
25
|
+
* def's `qualifiedName`. Returns undefined when there is no enclosing class/module.
|
|
26
|
+
*/
|
|
27
|
+
function buildEnclosingQualifiedName(callNode) {
|
|
28
|
+
const segments = [];
|
|
29
|
+
let current = callNode.parent;
|
|
30
|
+
while (current !== null) {
|
|
31
|
+
if (current.type === 'class' || current.type === 'module') {
|
|
32
|
+
const nameNode = current.childForFieldName('name');
|
|
33
|
+
if (nameNode !== null)
|
|
34
|
+
segments.unshift(...splitQualifiedName(nameNode.text));
|
|
35
|
+
}
|
|
36
|
+
// Stop at the file root — nothing above `program` contributes a Ruby
|
|
37
|
+
// class/module scope segment (#1982 perf; avoids walking to the very top
|
|
38
|
+
// for every heritage/attr call).
|
|
39
|
+
if (current.type === 'program')
|
|
40
|
+
break;
|
|
41
|
+
current = current.parent;
|
|
42
|
+
}
|
|
43
|
+
return segments.length > 0 ? segments.join('.') : undefined;
|
|
44
|
+
}
|
|
14
45
|
export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
15
46
|
let tree = cachedTree;
|
|
16
47
|
if (tree === undefined) {
|
|
@@ -37,18 +68,25 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
37
68
|
const out = [];
|
|
38
69
|
for (const m of rawMatches) {
|
|
39
70
|
const grouped = {};
|
|
71
|
+
// Parallel tag -> captured SyntaxNode map. The query already hands us each
|
|
72
|
+
// matched node as c.node, so anchors are used directly (via nodeIfType)
|
|
73
|
+
// instead of re-deriving them with findNodeAtRange(tree.rootNode, ...) per
|
|
74
|
+
// match — the O(matches x rootChildren) root-walk fixed for go #1915 /
|
|
75
|
+
// python #1918, mirrored here.
|
|
76
|
+
const nodeMap = {};
|
|
40
77
|
for (const c of m.captures) {
|
|
41
78
|
const tag = '@' + c.name;
|
|
42
79
|
if (tag.startsWith('@_'))
|
|
43
80
|
continue;
|
|
44
81
|
grouped[tag] = nodeToCapture(tag, c.node);
|
|
82
|
+
nodeMap[tag] = c.node;
|
|
45
83
|
}
|
|
46
84
|
if (Object.keys(grouped).length === 0)
|
|
47
85
|
continue;
|
|
48
86
|
// Decompose require/require_relative/load into import captures
|
|
49
87
|
if (grouped['@import.statement'] !== undefined) {
|
|
50
88
|
const anchor = grouped['@import.statement'];
|
|
51
|
-
const callNode =
|
|
89
|
+
const callNode = nodeIfType(nodeMap['@import.statement'], 'call');
|
|
52
90
|
if (callNode !== null) {
|
|
53
91
|
const decomposed = decomposeRubyImport(callNode, anchor);
|
|
54
92
|
if (decomposed !== null) {
|
|
@@ -61,8 +99,7 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
61
99
|
}
|
|
62
100
|
// Synthesize self receiver bindings for methods inside class/module
|
|
63
101
|
if (grouped['@scope.function'] !== undefined) {
|
|
64
|
-
const
|
|
65
|
-
const fnNode = findFunctionNode(tree.rootNode, scopeCap.range);
|
|
102
|
+
const fnNode = nodeIfType(nodeMap['@scope.function'], ...FUNCTION_NODE_TYPES);
|
|
66
103
|
if (fnNode !== null) {
|
|
67
104
|
const enclosingNode = findEnclosingClassOrModule(fnNode);
|
|
68
105
|
const receiver = synthesizeRubyReceiverBinding(fnNode, enclosingNode);
|
|
@@ -74,8 +111,7 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
74
111
|
}
|
|
75
112
|
// Reclassify declaration.function as declaration.method + attach arity
|
|
76
113
|
if (grouped['@declaration.function'] !== undefined) {
|
|
77
|
-
const
|
|
78
|
-
const fnNode = findFunctionNode(tree.rootNode, anchorCap.range);
|
|
114
|
+
const fnNode = nodeIfType(nodeMap['@declaration.function'], ...FUNCTION_NODE_TYPES);
|
|
79
115
|
if (fnNode !== null) {
|
|
80
116
|
const enclosingNode = findEnclosingClassOrModule(fnNode);
|
|
81
117
|
if (enclosingNode !== null) {
|
|
@@ -105,21 +141,27 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
105
141
|
if (grouped['@reference.call.free'] !== undefined && grouped['@reference.name'] !== undefined) {
|
|
106
142
|
const callName = grouped['@reference.name'].text;
|
|
107
143
|
if (HERITAGE_CALL_NAMES.has(callName)) {
|
|
108
|
-
const callNode =
|
|
144
|
+
const callNode = nodeIfType(nodeMap['@reference.call.free'], 'call');
|
|
109
145
|
if (callNode !== null) {
|
|
110
|
-
const
|
|
111
|
-
const ownerName = enclosing?.childForFieldName('name')?.text;
|
|
146
|
+
const ownerName = buildEnclosingQualifiedName(callNode);
|
|
112
147
|
if (ownerName) {
|
|
113
148
|
const argList = callNode.childForFieldName('arguments');
|
|
114
149
|
if (argList !== null) {
|
|
115
150
|
for (let ai = 0; ai < argList.namedChildCount; ai++) {
|
|
116
151
|
const arg = argList.namedChild(ai);
|
|
117
152
|
if (arg !== null && (arg.type === 'constant' || arg.type === 'scope_resolution')) {
|
|
153
|
+
// Normalize a qualified mixin arg (`Outer::Mixin`) to its dotted
|
|
154
|
+
// form (`Outer.Mixin`) BEFORE embedding it in the ':'-delimited
|
|
155
|
+
// __heritage__ marker: the raw `::` collides with the marker's `:`
|
|
156
|
+
// field separator and emitRubyMixinEdges mis-splits it, dropping
|
|
157
|
+
// the edge (#1982). The dotted form also matches the mixin def's
|
|
158
|
+
// qualifiedName key for resolution. Simple names are unchanged.
|
|
159
|
+
const mixinName = splitQualifiedName(arg.text).join('.');
|
|
118
160
|
out.push({
|
|
119
161
|
'@import.statement': grouped['@reference.call.free'],
|
|
120
162
|
'@import.kind': syntheticCapture('@import.kind', callNode, 'namespace'),
|
|
121
|
-
'@import.source': syntheticCapture('@import.source', callNode,
|
|
122
|
-
'@import.name': syntheticCapture('@import.name', callNode,
|
|
163
|
+
'@import.source': syntheticCapture('@import.source', callNode, encodeMarker('heritage', [callName, mixinName, ownerName])),
|
|
164
|
+
'@import.name': syntheticCapture('@import.name', callNode, mixinName),
|
|
123
165
|
});
|
|
124
166
|
}
|
|
125
167
|
}
|
|
@@ -134,21 +176,20 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
134
176
|
// localDefs and gets reconciled into model.fields, enabling write-access
|
|
135
177
|
// resolution via receiver-bound-calls (Case 4 → findOwnedMember).
|
|
136
178
|
if (ATTR_CALL_NAMES.has(callName)) {
|
|
137
|
-
const callNode =
|
|
179
|
+
const callNode = nodeIfType(nodeMap['@reference.call.free'], 'call');
|
|
138
180
|
if (callNode !== null) {
|
|
139
|
-
const
|
|
140
|
-
const ownerName = enclosing?.childForFieldName('name')?.text;
|
|
181
|
+
const ownerName = buildEnclosingQualifiedName(callNode);
|
|
141
182
|
if (ownerName) {
|
|
142
183
|
const argList = callNode.childForFieldName('arguments');
|
|
143
184
|
if (argList !== null) {
|
|
144
185
|
for (let ai = 0; ai < argList.namedChildCount; ai++) {
|
|
145
186
|
const arg = argList.namedChild(ai);
|
|
146
|
-
if (arg !== null &&
|
|
187
|
+
if (arg !== null && arg.type === 'simple_symbol') {
|
|
147
188
|
const propName = arg.text.replace(/^:/, '');
|
|
148
189
|
out.push({
|
|
149
190
|
'@import.statement': grouped['@reference.call.free'],
|
|
150
191
|
'@import.kind': syntheticCapture('@import.kind', callNode, 'namespace'),
|
|
151
|
-
'@import.source': syntheticCapture('@import.source', callNode,
|
|
192
|
+
'@import.source': syntheticCapture('@import.source', callNode, encodeMarker('property', [callName, propName, ownerName])),
|
|
152
193
|
'@import.name': syntheticCapture('@import.name', callNode, propName),
|
|
153
194
|
});
|
|
154
195
|
// Emit a property declaration so the property flows into
|
|
@@ -168,8 +209,7 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
168
209
|
// Attach call arity for call expressions
|
|
169
210
|
const callTag = ['@reference.call.free', '@reference.call.member'].find((t) => grouped[t] !== undefined);
|
|
170
211
|
if (callTag !== undefined && grouped['@reference.arity'] === undefined) {
|
|
171
|
-
const
|
|
172
|
-
const callNode = findNodeAtRange(tree.rootNode, anchor.range, 'call');
|
|
212
|
+
const callNode = nodeIfType(nodeMap[callTag], 'call');
|
|
173
213
|
if (callNode !== null) {
|
|
174
214
|
const arity = computeRubyCallArity(callNode);
|
|
175
215
|
grouped['@reference.arity'] = syntheticCapture('@reference.arity', callNode, String(arity));
|
|
@@ -261,7 +301,7 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
261
301
|
if (argList !== null) {
|
|
262
302
|
for (let ai = 0; ai < argList.namedChildCount; ai++) {
|
|
263
303
|
const arg = argList.namedChild(ai);
|
|
264
|
-
if (arg !== null &&
|
|
304
|
+
if (arg !== null && arg.type === 'simple_symbol') {
|
|
265
305
|
const propName = arg.text.replace(/^:/, '');
|
|
266
306
|
out.push({
|
|
267
307
|
'@type-binding.return': syntheticCapture('@type-binding.return', attrNode, text),
|
|
@@ -293,6 +333,29 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
293
333
|
// return-type binding `methodName → ClassName` on the method node.
|
|
294
334
|
// This enables cross-file return-type propagation for factory methods
|
|
295
335
|
// like `def self.get_user; User.new; end` → `get_user → User`.
|
|
336
|
+
// Keys of methods that already got a return binding from the YARD pass above,
|
|
337
|
+
// precomputed once. The previous `out.some(...)` per method was
|
|
338
|
+
// O(methods x out.length) ~ O(n^2); this makes the dedup O(1) per method.
|
|
339
|
+
// Key = `<name>:<return-binding startLine>`, matching the old AND condition.
|
|
340
|
+
//
|
|
341
|
+
// Snapshot-vs-live note (PR #1918 tri-review P3): the old `out.some` was
|
|
342
|
+
// evaluated LIVE, so it also saw constructor-return bindings this very loop
|
|
343
|
+
// pushed in earlier iterations. That made the old code suppress the 2nd of
|
|
344
|
+
// two same-named methods one source row apart whose bodies both end in
|
|
345
|
+
// `Const.new` (the 1st's pushed binding startLine == the 2nd's row via the
|
|
346
|
+
// 1-based/0-based offset below). The snapshot is built from the YARD pass
|
|
347
|
+
// only, so it no longer cross-suppresses — both bindings are emitted, which
|
|
348
|
+
// is the intended behavior (the cross-suppression was unintended). This
|
|
349
|
+
// corner is absent from fixtures, so the capture fingerprint is unchanged;
|
|
350
|
+
// ruby-captures-golden.test.ts pins it explicitly.
|
|
351
|
+
const yardReturnKeys = new Set();
|
|
352
|
+
for (const m of out) {
|
|
353
|
+
const ret = m['@type-binding.return'];
|
|
354
|
+
const name = m['@type-binding.name'];
|
|
355
|
+
if (ret !== undefined && name !== undefined) {
|
|
356
|
+
yardReturnKeys.add(`${name.text}:${ret.range.startLine}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
296
359
|
for (const methodNode of [
|
|
297
360
|
...tree.rootNode.descendantsOfType('method'),
|
|
298
361
|
...tree.rootNode.descendantsOfType('singleton_method'),
|
|
@@ -300,10 +363,8 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
300
363
|
const methodName = methodNode.childForFieldName('name')?.text;
|
|
301
364
|
if (methodName === undefined)
|
|
302
365
|
continue;
|
|
303
|
-
// Skip if a YARD @return already created a return binding for this method
|
|
304
|
-
if (
|
|
305
|
-
m['@type-binding.name']?.text === methodName &&
|
|
306
|
-
m['@type-binding.return']?.range.startLine === methodNode.startPosition.row)) {
|
|
366
|
+
// Skip if a YARD @return already created a return binding for this method.
|
|
367
|
+
if (yardReturnKeys.has(`${methodName}:${methodNode.startPosition.row}`)) {
|
|
307
368
|
continue;
|
|
308
369
|
}
|
|
309
370
|
const body = methodNode.childForFieldName('body');
|
|
@@ -329,8 +390,98 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
|
|
|
329
390
|
}
|
|
330
391
|
}
|
|
331
392
|
}
|
|
393
|
+
// Fifth pass: superclass inheritance (`class Foo < Bar`).
|
|
394
|
+
// Emit `@reference.inherits` captures so the registry-primary scope-
|
|
395
|
+
// resolution path produces EXTENDS edges (issue #1951). This mirrors the
|
|
396
|
+
// C#/C++ inheritance synthesis: Ruby's superclass edges previously came
|
|
397
|
+
// only from the legacy heritage-capture query (removed in #942), which the
|
|
398
|
+
// worker pipeline drops for registry-primary languages → 0 inheritance edges
|
|
399
|
+
// in worker mode. Mixins (include/extend/prepend) are NOT touched here — they
|
|
400
|
+
// flow through `emitHeritageEdges` (the `__heritage__:` import path above),
|
|
401
|
+
// an independent lane that stays intact when the legacy heritage leg is gated off.
|
|
402
|
+
out.push(...synthesizeRubySuperclassReferences(tree.rootNode));
|
|
403
|
+
return out;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Synthesize `@reference.inherits` captures from Ruby `class Foo < Bar`
|
|
407
|
+
* superclass declarations so the shared `preEmitInheritanceEdges` pass can
|
|
408
|
+
* resolve the base to a Class def and emit an EXTENDS edge.
|
|
409
|
+
*
|
|
410
|
+
* Scope is `class` nodes whose `superclass` field holds either a bare
|
|
411
|
+
* `constant` base (`class D < Super`) or a qualified/scoped
|
|
412
|
+
* `scope_resolution` base (`class C < Outer::Super`, `class E < A::B::C`) —
|
|
413
|
+
* exactly the two shapes the config-driven legacy heritage alternation
|
|
414
|
+
* captured (heritage-extractors/configs/ruby.ts
|
|
415
|
+
* `rubyHeritageShapes: ['constant', 'scope_resolution']`). In prose: the
|
|
416
|
+
* legacy query matched a `class` whose name is a `constant` and whose
|
|
417
|
+
* `superclass` is either a `constant` or a `scope_resolution`, capturing the
|
|
418
|
+
* superclass constant as the inherited base.
|
|
419
|
+
*
|
|
420
|
+
* Previously this pass emitted only for a direct `(constant)` child, so the
|
|
421
|
+
* production registry-primary path silently dropped `Outer::Super`
|
|
422
|
+
* superclasses while the legacy heritage leg captured them — the exact
|
|
423
|
+
* EXTENDS/IMPLEMENTS-drop bug of #1951.
|
|
424
|
+
*
|
|
425
|
+
* THE PARITY CONTRACT: the `@reference.name` bare text must equal the legacy
|
|
426
|
+
* leg's `normalizeSupertypeName(baseNode)` reduction. For a `scope_resolution`
|
|
427
|
+
* (`Outer::Super`, `A::B::C`) the normalizer recurses into the `name:` field
|
|
428
|
+
* and returns the trailing `constant` (`Super` / `C`); this synth mirrors that
|
|
429
|
+
* by reading the same `name:` tail. A bare `constant` is unchanged
|
|
430
|
+
* (byte-identical to the prior emission). `module` nodes are excluded (no
|
|
431
|
+
* superclass field). Mixins (include/extend/prepend) are untouched — they flow
|
|
432
|
+
* through the `__heritage__:` import lane above.
|
|
433
|
+
*
|
|
434
|
+
* Edge type (EXTENDS vs IMPLEMENTS) is decided downstream from the resolved
|
|
435
|
+
* target's symbol kind — this pass only emits `@reference.inherits`.
|
|
436
|
+
*/
|
|
437
|
+
function synthesizeRubySuperclassReferences(root) {
|
|
438
|
+
const out = [];
|
|
439
|
+
walkNamedTree(root, (node) => {
|
|
440
|
+
if (node.type !== 'class')
|
|
441
|
+
return;
|
|
442
|
+
const superclass = node.childForFieldName('superclass');
|
|
443
|
+
if (superclass === null)
|
|
444
|
+
return;
|
|
445
|
+
const baseNode = extractRubySuperclassBaseNode(superclass);
|
|
446
|
+
if (baseNode === null)
|
|
447
|
+
return;
|
|
448
|
+
out.push({
|
|
449
|
+
'@reference.inherits': nodeToCapture('@reference.inherits', baseNode),
|
|
450
|
+
'@reference.name': nodeToCapture('@reference.name', baseNode),
|
|
451
|
+
});
|
|
452
|
+
});
|
|
332
453
|
return out;
|
|
333
454
|
}
|
|
455
|
+
/**
|
|
456
|
+
* Reduce a Ruby `superclass` node to the bare `constant` the resolver should
|
|
457
|
+
* look up, at parity with the legacy heritage leg's
|
|
458
|
+
* `normalizeSupertypeName(baseNode)`:
|
|
459
|
+
*
|
|
460
|
+
* - direct `(constant)` child (`class D < Super`) → that constant
|
|
461
|
+
* (unchanged from the original emission — kept byte-identical)
|
|
462
|
+
* - `(scope_resolution)` child (`class C < Outer::Super`,
|
|
463
|
+
* `class E < A::B::C`) → the trailing
|
|
464
|
+
* `name:` constant (`Super` / `C`)
|
|
465
|
+
*
|
|
466
|
+
* A `scope_resolution` nests qualifier-first, name-last
|
|
467
|
+
* (`scope: (...) name: (constant)`), so the `name:` field is always the
|
|
468
|
+
* trailing simple identifier — the same tail `normalizeSupertypeName` reaches
|
|
469
|
+
* by recursing through its `name` field. Any other shape returns null (no
|
|
470
|
+
* edge), keeping this emitter at parity with the legacy alternation
|
|
471
|
+
* (`['constant', 'scope_resolution']`).
|
|
472
|
+
*/
|
|
473
|
+
function extractRubySuperclassBaseNode(superclass) {
|
|
474
|
+
const directConstant = findChild(superclass, 'constant');
|
|
475
|
+
if (directConstant !== null)
|
|
476
|
+
return directConstant;
|
|
477
|
+
const scoped = findChild(superclass, 'scope_resolution');
|
|
478
|
+
if (scoped !== null) {
|
|
479
|
+
const tail = scoped.childForFieldName('name');
|
|
480
|
+
if (tail !== null && tail.type === 'constant')
|
|
481
|
+
return tail;
|
|
482
|
+
}
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
334
485
|
function decomposeRubyImport(callNode, anchor) {
|
|
335
486
|
const methodNode = callNode.childForFieldName('method');
|
|
336
487
|
if (methodNode === null)
|
|
@@ -431,14 +582,6 @@ function computeRubyCallArity(callNode) {
|
|
|
431
582
|
}
|
|
432
583
|
return count;
|
|
433
584
|
}
|
|
434
|
-
function findFunctionNode(rootNode, range) {
|
|
435
|
-
for (const nodeType of FUNCTION_NODE_TYPES) {
|
|
436
|
-
const n = findNodeAtRange(rootNode, range, nodeType);
|
|
437
|
-
if (n !== null)
|
|
438
|
-
return n;
|
|
439
|
-
}
|
|
440
|
-
return null;
|
|
441
|
-
}
|
|
442
585
|
function scopeExtractionError(stage, filePath, err) {
|
|
443
586
|
const reason = err instanceof Error ? err.message : String(err);
|
|
444
587
|
return new Error(`[ruby] tree-sitter ${stage} failed for ${filePath}: ${reason}; skipping scope extraction for this file`);
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { resolveRubyImportInternal } from '../../import-resolvers/ruby.js';
|
|
10
10
|
import { buildSuffixIndex } from '../../import-resolvers/utils.js';
|
|
11
|
+
import { isHeritageMarker } from '../../utils/heritage-marker.js';
|
|
11
12
|
// ─── resolveRubyImportTarget ──────────────────────────────────────────────
|
|
12
13
|
/**
|
|
13
14
|
* ScopeResolver-shaped adapter:
|
|
@@ -25,7 +26,7 @@ import { buildSuffixIndex } from '../../import-resolvers/utils.js';
|
|
|
25
26
|
export function resolveRubyImportTarget(targetRaw, fromFile, allFilePaths, _resolutionConfig) {
|
|
26
27
|
if (!targetRaw)
|
|
27
28
|
return null;
|
|
28
|
-
if (
|
|
29
|
+
if (isHeritageMarker(targetRaw))
|
|
29
30
|
return null;
|
|
30
31
|
const fromNormalized = fromFile.replace(/\\/g, '/');
|
|
31
32
|
const fromDir = fromNormalized.includes('/')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isHeritageMarker } from '../../utils/heritage-marker.js';
|
|
1
2
|
// ─── interpretImport ──────────────────────────────────────────────────────
|
|
2
3
|
/**
|
|
3
4
|
* Interpret a pre-decomposed Ruby import capture into a `ParsedImport`.
|
|
@@ -18,7 +19,7 @@ export function interpretRubyImport(captures) {
|
|
|
18
19
|
return null;
|
|
19
20
|
// Heritage-encoded imports (__heritage__:include:Serializable:User)
|
|
20
21
|
// are stored as namespace imports so emitHeritageEdges can read them.
|
|
21
|
-
if (
|
|
22
|
+
if (isHeritageMarker(source)) {
|
|
22
23
|
const name = captures['@import.name']?.text ?? source;
|
|
23
24
|
return { kind: 'namespace', localName: name, importedName: name, targetRaw: source };
|
|
24
25
|
}
|
|
@@ -52,11 +52,21 @@ const RUBY_SCOPE_QUERY = `
|
|
|
52
52
|
(class
|
|
53
53
|
name: (constant) @declaration.name) @declaration.class
|
|
54
54
|
|
|
55
|
+
;; class Foo::Bar — namespaced class definition
|
|
56
|
+
(class
|
|
57
|
+
name: (scope_resolution
|
|
58
|
+
name: (constant) @declaration.name)) @declaration.class
|
|
59
|
+
|
|
55
60
|
;; ── Declarations — module (labeled Trait for class-like registry lookup) ─
|
|
56
61
|
|
|
57
62
|
(module
|
|
58
63
|
name: (constant) @declaration.name) @declaration.trait
|
|
59
64
|
|
|
65
|
+
;; module Baz::Qux — namespaced module definition
|
|
66
|
+
(module
|
|
67
|
+
name: (scope_resolution
|
|
68
|
+
name: (constant) @declaration.name)) @declaration.trait
|
|
69
|
+
|
|
60
70
|
;; ── Declarations — method (instance) ─────────────────────────────────────
|
|
61
71
|
|
|
62
72
|
(method
|
|
@@ -5,17 +5,59 @@ import { rubyArityCompatibility, rubyMergeBindings, resolveRubyImportTarget } fr
|
|
|
5
5
|
import { populateClassOwnedMembers, isClassLike } from '../../scope-resolution/scope/walkers.js';
|
|
6
6
|
import { resolveDefGraphId } from '../../scope-resolution/graph-bridge/ids.js';
|
|
7
7
|
import { generateId } from '../../../../lib/utils.js';
|
|
8
|
-
|
|
8
|
+
import { decodeMarker } from '../../utils/heritage-marker.js';
|
|
9
|
+
/**
|
|
10
|
+
* #1991: resolve a BARE mixin reference (`include Loggable`) to a nested module by
|
|
11
|
+
* the INCLUDING class's lexical scope — Ruby looks up a constant in the innermost
|
|
12
|
+
* enclosing scope first. For owner `App.S`, try `App.Loggable`, then walk outward.
|
|
13
|
+
* Returns undefined if no enclosing-scope-qualified module exists.
|
|
14
|
+
*/
|
|
15
|
+
function qualifyMixinByOwnerScope(mixinName, ownerName, graphIdByName) {
|
|
16
|
+
let prefix = ownerName;
|
|
17
|
+
let dot = prefix.lastIndexOf('.');
|
|
18
|
+
while (dot !== -1) {
|
|
19
|
+
prefix = prefix.slice(0, dot);
|
|
20
|
+
const g = graphIdByName.get(`${prefix}.${mixinName}`);
|
|
21
|
+
if (g !== undefined)
|
|
22
|
+
return g;
|
|
23
|
+
dot = prefix.lastIndexOf('.');
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
9
27
|
function emitRubyMixinEdges(graph, parsedFiles, nodeLookup) {
|
|
10
28
|
const graphIdByName = new Map();
|
|
29
|
+
// Secondary tail -> graphId map. The `__heritage__` marker carries the mixin
|
|
30
|
+
// TARGET as the bare written name (`arg.text`, e.g. `Loggable`), not its full
|
|
31
|
+
// qualifiedName, so a nested mixin module included by its short name misses the
|
|
32
|
+
// full-qn map. We first resolve it lexically by the including class's enclosing
|
|
33
|
+
// scope (`qualifyMixinByOwnerScope`); this tail map is the last resort. A genuine
|
|
34
|
+
// same-tail collision is mapped to `null` so we REFUSE to guess (#1991) rather
|
|
35
|
+
// than the old first-wins, which cross-wired App::Loggable / Web::Loggable.
|
|
36
|
+
const graphIdByTail = new Map();
|
|
11
37
|
for (const parsed of parsedFiles) {
|
|
12
38
|
for (const def of parsed.localDefs) {
|
|
13
39
|
if (!isClassLike(def.type))
|
|
14
40
|
continue;
|
|
15
41
|
const graphId = resolveDefGraphId(parsed.filePath, def, nodeLookup);
|
|
16
42
|
if (graphId !== undefined) {
|
|
17
|
-
|
|
18
|
-
|
|
43
|
+
// Key by the FULL qualified name (`Outer.Inner`), NOT the simple tail.
|
|
44
|
+
// Same-tail nested classes (`Outer::Inner` + `Other::Inner`) otherwise
|
|
45
|
+
// collapse onto one `Inner` key (last-wins) and cross-wire their mixin /
|
|
46
|
+
// attr_accessor owners (#1982). The `__heritage__`/`__property__` markers
|
|
47
|
+
// carry the full qualified owner name in lockstep (see ruby/captures.ts).
|
|
48
|
+
const fullName = def.qualifiedName ?? '';
|
|
49
|
+
if (fullName.length > 0) {
|
|
50
|
+
graphIdByName.set(fullName, graphId);
|
|
51
|
+
const dot = fullName.lastIndexOf('.');
|
|
52
|
+
const tail = dot === -1 ? fullName : fullName.slice(dot + 1);
|
|
53
|
+
if (tail.length > 0) {
|
|
54
|
+
const existingTail = graphIdByTail.get(tail);
|
|
55
|
+
if (existingTail === undefined)
|
|
56
|
+
graphIdByTail.set(tail, graphId);
|
|
57
|
+
else if (existingTail !== null && existingTail !== graphId)
|
|
58
|
+
graphIdByTail.set(tail, null); // same-tail collision — refuse to guess
|
|
59
|
+
}
|
|
60
|
+
}
|
|
19
61
|
}
|
|
20
62
|
}
|
|
21
63
|
}
|
|
@@ -28,14 +70,22 @@ function emitRubyMixinEdges(graph, parsedFiles, nodeLookup) {
|
|
|
28
70
|
}
|
|
29
71
|
for (const parsed of parsedFiles) {
|
|
30
72
|
for (const imp of parsed.parsedImports) {
|
|
31
|
-
|
|
73
|
+
const decoded = decodeMarker(imp.targetRaw);
|
|
74
|
+
if (decoded?.kind !== 'heritage')
|
|
32
75
|
continue;
|
|
33
|
-
const parts =
|
|
76
|
+
const parts = decoded.fields;
|
|
34
77
|
if (parts.length < 3)
|
|
35
78
|
continue;
|
|
36
79
|
const [kind, mixinName, className] = parts;
|
|
37
80
|
const classGraphId = graphIdByName.get(className);
|
|
38
|
-
|
|
81
|
+
// Owner stays full-qn. The mixin target may be written by short name and miss
|
|
82
|
+
// the full-qn map; resolve it lexically by the including class's enclosing
|
|
83
|
+
// scope (`App::S` + `Loggable` -> `App::Loggable`), then fall back to the tail
|
|
84
|
+
// map ONLY when unambiguous — never first-wins on a collision (#1982/#1991).
|
|
85
|
+
const mixinGraphId = graphIdByName.get(mixinName) ??
|
|
86
|
+
qualifyMixinByOwnerScope(mixinName, className, graphIdByName) ??
|
|
87
|
+
graphIdByTail.get(mixinName) ??
|
|
88
|
+
undefined;
|
|
39
89
|
if (classGraphId === undefined || mixinGraphId === undefined)
|
|
40
90
|
continue;
|
|
41
91
|
const edgeKey = `${classGraphId}->${mixinGraphId}:${kind}`;
|
|
@@ -62,12 +112,12 @@ function emitRubyMixinEdges(graph, parsedFiles, nodeLookup) {
|
|
|
62
112
|
existingProps.add(`${rel.sourceId}->prop:${targetNode.properties.name}`);
|
|
63
113
|
}
|
|
64
114
|
}
|
|
65
|
-
const PROPERTY_PREFIX = '__property__:';
|
|
66
115
|
for (const parsed of parsedFiles) {
|
|
67
116
|
for (const imp of parsed.parsedImports) {
|
|
68
|
-
|
|
117
|
+
const decoded = decodeMarker(imp.targetRaw);
|
|
118
|
+
if (decoded?.kind !== 'property')
|
|
69
119
|
continue;
|
|
70
|
-
const parts =
|
|
120
|
+
const parts = decoded.fields;
|
|
71
121
|
if (parts.length < 3)
|
|
72
122
|
continue;
|
|
73
123
|
const [_attrKind, propName, className] = parts;
|
|
@@ -137,8 +187,8 @@ function buildRubyMro(graph, parsedFiles, nodeLookup) {
|
|
|
137
187
|
}
|
|
138
188
|
// Step 4: Reorder MRO per Ruby semantics.
|
|
139
189
|
// Order: prepend (reversed) → direct extends chain → include (reversed).
|
|
140
|
-
// `extend` is excluded — it belongs to singleton dispatch only (
|
|
141
|
-
//
|
|
190
|
+
// `extend` is excluded — it belongs to singleton dispatch only (the
|
|
191
|
+
// instance-ancestry walk drops extend entries).
|
|
142
192
|
// Reversed because Ruby declaration order means last-declared wins
|
|
143
193
|
// (prepend B; prepend A → B checked before A).
|
|
144
194
|
for (const defId of defIdByGraphId.values()) {
|
|
@@ -24,10 +24,6 @@ import { createVariableExtractor } from '../variable-extractors/generic.js';
|
|
|
24
24
|
import { rubyVariableConfig } from '../variable-extractors/configs/ruby.js';
|
|
25
25
|
import { createCallExtractor } from '../call-extractors/generic.js';
|
|
26
26
|
import { rubyCallConfig } from '../call-extractors/configs/ruby.js';
|
|
27
|
-
import { createHeritageExtractor } from '../heritage-extractors/generic.js';
|
|
28
|
-
import { rubyHeritageConfig } from '../heritage-extractors/configs/ruby.js';
|
|
29
|
-
import { maybeRewriteRubyBareCallToSelf } from '../utils/ruby-self-call.js';
|
|
30
|
-
import { findEnclosingClassInfo } from '../utils/ast-helpers.js';
|
|
31
27
|
import { emitRubyScopeCaptures, rubyArityCompatibility, rubyBindingScopeFor, rubyImportOwningScope, rubyReceiverBinding, interpretRubyImport, interpretRubyTypeBinding, } from './ruby/index.js';
|
|
32
28
|
/**
|
|
33
29
|
* Ruby label override. Applied to:
|
|
@@ -122,7 +118,8 @@ const BUILT_INS = new Set([
|
|
|
122
118
|
/**
|
|
123
119
|
* Remaps `class << self` (singleton_class) to its enclosing class/module for
|
|
124
120
|
* receiver inference. A `singleton_class` node is not itself a type — walking
|
|
125
|
-
* up to the real owner
|
|
121
|
+
* up to the real owner resolves the singleton's enclosing class for the
|
|
122
|
+
* `resolveEnclosingOwner` scope-resolution hook.
|
|
126
123
|
* Returns null for orphaned singleton_class (no enclosing class/module found).
|
|
127
124
|
* All other container types are returned as-is.
|
|
128
125
|
*/
|
|
@@ -172,7 +169,6 @@ export const rubyProvider = defineLanguage({
|
|
|
172
169
|
exportChecker: rubyExportChecker,
|
|
173
170
|
importResolver: createImportResolver(rubyImportConfig),
|
|
174
171
|
callRouter: routeRubyCall,
|
|
175
|
-
importSemantics: 'wildcard-leaf',
|
|
176
172
|
callExtractor: createCallExtractor(rubyCallConfig),
|
|
177
173
|
resolveEnclosingOwner: rubyResolveEnclosingOwner,
|
|
178
174
|
fieldExtractor: createFieldExtractor(rubyFieldConfig),
|
|
@@ -182,56 +178,11 @@ export const rubyProvider = defineLanguage({
|
|
|
182
178
|
}),
|
|
183
179
|
variableExtractor: createVariableExtractor(rubyVariableConfig),
|
|
184
180
|
classExtractor: createClassExtractor(rubyClassConfig),
|
|
185
|
-
heritageExtractor: createHeritageExtractor(rubyHeritageConfig),
|
|
186
181
|
labelOverride: rubyLabelOverride,
|
|
187
182
|
// Ruby MRO is kind-aware: prepend providers beat the class's own method,
|
|
188
|
-
// which in turn beats include providers.
|
|
189
|
-
//
|
|
183
|
+
// which in turn beats include providers. The graph-level MRO phase
|
|
184
|
+
// (mro-processor.ts) and per-resolver buildMro consume this strategy.
|
|
190
185
|
mroStrategy: 'ruby-mixin',
|
|
191
|
-
// ── DAG hooks ────────────────────────────────────────────────────
|
|
192
|
-
//
|
|
193
|
-
// DAG stage 3: rewrite bare calls (e.g. `serialize` in Account#call_serialize)
|
|
194
|
-
// as `self.serialize` so they route through owner-scoped MRO instead of
|
|
195
|
-
// global free-call lookup. `dispatchKind` goes into `hint` for stage 4.
|
|
196
|
-
inferImplicitReceiver: ({ calledName, callForm, receiverName, receiverTypeName, callNode, filePath, }) => {
|
|
197
|
-
// Only fire when no receiver has been resolved already.
|
|
198
|
-
if (receiverName || receiverTypeName)
|
|
199
|
-
return null;
|
|
200
|
-
const enclosing = findEnclosingClassInfo(callNode, filePath, rubyResolveEnclosingOwner);
|
|
201
|
-
const rewrite = maybeRewriteRubyBareCallToSelf(calledName, callForm, callNode, enclosing?.className ?? null, { isBuiltInName: (n) => BUILT_INS.has(n), mroStrategy: 'ruby-mixin' });
|
|
202
|
-
if (!rewrite)
|
|
203
|
-
return null;
|
|
204
|
-
return {
|
|
205
|
-
callForm: rewrite.callForm,
|
|
206
|
-
receiverName: rewrite.receiverName,
|
|
207
|
-
receiverTypeName: rewrite.receiverTypeName,
|
|
208
|
-
receiverSource: 'implicit-self',
|
|
209
|
-
hint: rewrite.dispatchKind, // 'instance' | 'singleton'
|
|
210
|
-
};
|
|
211
|
-
},
|
|
212
|
-
// DAG stage 4: two Ruby dispatch overrides —
|
|
213
|
-
// implicit-self: MRO walk first, fallback to free-arity-narrowed on miss.
|
|
214
|
-
// class-as-receiver: singleton ancestry (extend providers only); miss null-routes.
|
|
215
|
-
selectDispatch: ({ receiverSource, hint }) => {
|
|
216
|
-
if (receiverSource === 'implicit-self') {
|
|
217
|
-
// hint='instance' → instance ancestry (prepend→direct→include, see mro-strategy.ts § 'ruby-mixin')
|
|
218
|
-
// hint='singleton' → singleton ancestry (extend providers only; miss null-routes)
|
|
219
|
-
const ancestryView = hint === 'singleton' ? 'singleton' : 'instance';
|
|
220
|
-
return {
|
|
221
|
-
primary: 'owner-scoped',
|
|
222
|
-
fallback: 'free-arity-narrowed',
|
|
223
|
-
ancestryView,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
if (receiverSource === 'class-as-receiver') {
|
|
227
|
-
// Class constant receiver (e.g. Account.log): singleton ancestry only; miss null-routes.
|
|
228
|
-
return {
|
|
229
|
-
primary: 'owner-scoped',
|
|
230
|
-
ancestryView: 'singleton',
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
return null;
|
|
234
|
-
},
|
|
235
186
|
builtInNames: BUILT_INS,
|
|
236
187
|
// ── RFC #909 Ring 3: scope-based resolution hooks ──────────
|
|
237
188
|
emitScopeCaptures: emitRubyScopeCaptures,
|