gitnexus 1.6.10-rc.67 → 1.6.10-rc.69
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/dist/core/ingestion/languages/java/captures.js +18 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +2 -1
- package/dist/core/lbug/lbug-adapter.d.ts +22 -1
- package/dist/core/lbug/lbug-adapter.js +27 -3
- package/dist/core/run-analyze.js +15 -2
- package/dist/core/search/fts-indexes.d.ts +9 -0
- package/dist/core/search/fts-indexes.js +13 -0
- package/dist/storage/repo-manager.d.ts +10 -2
- package/dist/storage/repo-manager.js +9 -1
- package/package.json +1 -1
|
@@ -110,6 +110,24 @@ export function emitJavaScopeCaptures(sourceText, filePath, cachedTree) {
|
|
|
110
110
|
grouped['@reference.receiver'] !== undefined) {
|
|
111
111
|
continue;
|
|
112
112
|
}
|
|
113
|
+
// Normalize a `new`-expression receiver to its constructed type's simple
|
|
114
|
+
// name: `new Local().inner()` binds the WHOLE `object_creation_expression`
|
|
115
|
+
// as `@reference.receiver`, so its raw text is `"new Local()"` — a string
|
|
116
|
+
// that can never match a scope binding, so the compound-receiver resolver
|
|
117
|
+
// silently falls through to name-only fallback resolution and picks the
|
|
118
|
+
// wrong same-named method on a collision (#2564). Rewriting the text to
|
|
119
|
+
// just `Local` lets Case 2 (class-name / static receiver) in
|
|
120
|
+
// receiver-bound-calls.ts resolve it via its normal MRO walk. Mirrors the
|
|
121
|
+
// established `normalizePhpReceiver` precedent (php/captures.ts) — a
|
|
122
|
+
// language-local capture rewrite, no shared-pipeline change.
|
|
123
|
+
if (grouped['@reference.receiver'] !== undefined) {
|
|
124
|
+
const receiverNode = nodeIfType(nodeMap['@reference.receiver'], 'object_creation_expression');
|
|
125
|
+
const typeNode = receiverNode?.childForFieldName('type');
|
|
126
|
+
const simpleName = typeNode ? javaBaseSimpleNameOf(typeNode) : undefined;
|
|
127
|
+
if (simpleName !== undefined) {
|
|
128
|
+
grouped['@reference.receiver'] = syntheticCapture('@reference.receiver', receiverNode, simpleName);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
113
131
|
// Filter read.member when it's a child of method_invocation or assignment.
|
|
114
132
|
// `@reference.read.member` is captured directly on the `field_access` node.
|
|
115
133
|
if (grouped['@reference.read.member'] !== undefined) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const TYPESCRIPT_QUERIES: string;
|
|
2
2
|
export declare const JAVASCRIPT_QUERIES: string;
|
|
3
3
|
export declare const PYTHON_QUERIES = "\n(class_definition\n name: (identifier) @name) @definition.class\n\n(function_definition\n name: (identifier) @name) @definition.function\n\n(import_statement\n name: (dotted_name) @import.source) @import\n\n; import numpy as np \u2192 aliased_import captures the module name so the\n; import path is resolved and named-binding extraction stores \"np\" \u2192 \"numpy\".\n(import_statement\n name: (aliased_import\n name: (dotted_name) @import.source)) @import\n\n(import_from_statement\n module_name: (dotted_name) @import.source) @import\n\n(import_from_statement\n module_name: (relative_import) @import.source) @import\n\n(call\n function: (identifier) @call.name) @call\n\n(call\n function: (attribute\n attribute: (identifier) @call.name)) @call\n\n; Class attribute type annotations \u2014 PEP 526: address: Address or address: Address = Address()\n; Both bare annotations (address: Address) and annotated assignments (name: str = \"test\")\n; are parsed as (assignment left: ... type: ...) in tree-sitter-python.\n(expression_statement\n (assignment\n left: (identifier) @name\n type: (type)) @definition.property)\n\n; Plain variable assignments without type annotation: x = 5, MAX_SIZE = 100\n; Overlap with @definition.property (typed) is handled by parse-worker dedup.\n(expression_statement\n (assignment\n left: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Write access: obj.field += value (compound assignment)\n(augmented_assignment\n left: (attribute\n object: (_) @assignment.receiver\n attribute: (identifier) @assignment.property)\n right: (_)) @assignment\n\n; Python HTTP clients: requests.get('/path'), httpx.post('/path'), session.get('/path')\n(call\n function: (attribute\n attribute: (identifier) @http_client.method)\n arguments: (argument_list\n (string (string_content) @http_client.url))) @http_client\n\n; Python decorators: @app.route, @router.get, etc.\n; The first positional argument is captured three ways (#2391): a string literal\n; path via @decorator.arg (quote-free, the fast path); a bare constant name or a\n; plus-concatenation via @decorator.arg_expr (resolved cross-file by the constant\n; resolver). The anchored optional alternation pins to the FIRST arg and stays\n; optional, so no-arg decorators (@app.tool(), etc.) and non-path first args still\n; match.\n(decorator\n (call\n function: (attribute\n object: (identifier) @decorator.receiver\n attribute: (identifier) @decorator.name)\n arguments: (argument_list\n .\n [\n (string (string_content)? @decorator.arg) @decorator.arg_str\n (identifier) @decorator.arg_expr\n (binary_operator) @decorator.arg_expr\n ]?))) @decorator\n";
|
|
4
|
-
export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Anonymous class bodies: new Runnable() { ... } \u2014 no @name capture; the\n; class extractor synthesizes the javac-style Worker$N name (#2550)\n(object_creation_expression (class_body)) @definition.class\n\n; Enum constant bodies: enum E { A { ... } } \u2014 javac's other anonymous\n; shape, synthesized as E$N by the same naming authority (#2555)\n(enum_constant body: (class_body)) @definition.class\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
|
|
4
|
+
export declare const JAVA_QUERIES = "\n; Classes, Interfaces, Enums, Records, Annotations\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(annotation_type_declaration name: (identifier) @name) @definition.annotation\n\n; Anonymous class bodies: new Runnable() { ... } \u2014 no @name capture; the\n; class extractor synthesizes the javac-style Worker$N name (#2550)\n(object_creation_expression (class_body)) @definition.class\n\n; Enum constant bodies: enum E { A { ... } } \u2014 javac's other anonymous\n; shape, synthesized as E$N by the same naming authority (#2555)\n(enum_constant body: (class_body)) @definition.class\n\n; Methods & Constructors\n(method_declaration name: (identifier) @name) @definition.method\n(constructor_declaration name: (identifier) @name) @definition.constructor\n\n; Fields \u2014 typed field declarations inside class bodies\n(field_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.property\n\n; Imports - capture any import declaration child as source\n(import_declaration (_) @import.source) @import\n\n; Calls\n(method_invocation name: (identifier) @call.name) @call\n(method_invocation object: (_) name: (identifier) @call.name) @call\n(method_reference) @call\n\n; Constructor calls: new Foo()\n(object_creation_expression type: (type_identifier) @call.name) @call\n\n; Local variable declarations inside method bodies\n(local_variable_declaration\n declarator: (variable_declarator\n name: (identifier) @name)) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_access\n object: (_) @assignment.receiver\n field: (identifier) @assignment.property)\n right: (_)) @assignment\n";
|
|
5
5
|
export declare const C_QUERIES = "\n; Functions (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n\n; Functions returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n\n; Functions returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n\n; Structs, Unions, Enums, Typedefs\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(union_specifier name: (type_identifier) @name) @definition.union\n(enum_specifier name: (type_identifier) @name) @definition.enum\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n\n; Variable declarations: int x = 5; or int x;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n";
|
|
6
6
|
export declare const GO_QUERIES = "\n; Functions & Methods\n(function_declaration name: (identifier) @name) @definition.function\n(method_declaration name: (field_identifier) @name) @definition.method\n(method_elem name: (field_identifier) @name) @definition.method\n\n; Types\n(type_declaration (type_spec name: (type_identifier) @name type: (struct_type))) @definition.struct\n(type_declaration (type_spec name: (type_identifier) @name type: (interface_type))) @definition.interface\n\n; Imports\n(import_declaration (import_spec path: (interpreted_string_literal) @import.source)) @import\n(import_declaration (import_spec_list (import_spec path: (interpreted_string_literal) @import.source))) @import\n\n; Struct fields \u2014 named field declarations inside struct types\n(field_declaration_list\n (field_declaration\n name: (field_identifier) @name) @definition.property)\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (selector_expression field: (field_identifier) @call.name)) @call\n\n; Const/var declarations\n(const_declaration (const_spec (identifier) @name)) @definition.const\n(var_declaration (var_spec (identifier) @name)) @definition.variable\n(var_declaration (var_spec_list (var_spec (identifier) @name))) @definition.variable\n\n; Short variable declaration: x := 5\n(short_var_declaration left: (expression_list (identifier) @name)) @definition.variable\n\n; Struct literal construction: User{Name: \"Alice\"}\n(composite_literal type: (type_identifier) @call.name) @call\n\n; Write access: obj.field = value\n(assignment_statement\n left: (expression_list\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property))\n right: (_)) @assignment\n\n; Write access: obj.field++ / obj.field--\n(inc_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n(dec_statement\n (selector_expression\n operand: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)) @assignment\n";
|
|
7
7
|
export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_specifier name: (type_identifier) @name) @definition.class\n(class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.class\n; Out-of-line nested definition: class Outer::Inner { ... } / struct Outer::Inner { ... }.\n; Key the node by the full qualified_identifier text so the def materializes a\n; node that matches the HAS_METHOD owner id (also the full qualified text) and\n; stays distinct from a same-tail type in another scope (#1975, #1978).\n(class_specifier name: (qualified_identifier) @name) @definition.class\n(struct_specifier name: (qualified_identifier) @name) @definition.struct\n(struct_specifier name: (type_identifier) @name) @definition.struct\n(struct_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments)) @definition.struct\n(namespace_definition name: (namespace_identifier) @name) @definition.namespace\n(enum_specifier name: (type_identifier) @name) @definition.enum\n\n; Typedefs and unions (common in C-style headers and mixed C/C++ code)\n(type_definition\n type: (struct_specifier\n body: (field_declaration_list))\n declarator: (type_identifier) @name) @definition.struct\n(type_definition\n type: (enum_specifier\n body: (enumerator_list))\n declarator: (type_identifier) @name) @definition.enum\n(enumerator name: (identifier) @name) @definition.const\n(type_definition declarator: (type_identifier) @name) @definition.typedef\n(union_specifier name: (type_identifier) @name) @definition.union\n\n; Macros\n(preproc_function_def name: (identifier) @name) @definition.macro\n(preproc_def name: (identifier) @name) @definition.macro\n\n; Functions & Methods (direct declarator)\n(function_definition declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))) @definition.method\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (operator_name) @name))) @definition.method\n\n; Functions/methods returning pointers (pointer_declarator wraps function_declarator)\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n\n; Functions/methods returning double pointers (nested pointer_declarator)\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name)))) @definition.function\n(function_definition declarator: (pointer_declarator declarator: (pointer_declarator declarator: (function_declarator declarator: (qualified_identifier name: (identifier) @name))))) @definition.method\n\n; Functions/methods returning references (reference_declarator wraps function_declarator)\n(function_definition declarator: (reference_declarator (function_declarator declarator: (identifier) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (identifier) @name)))) @definition.method\n(function_definition declarator: (reference_declarator (function_declarator declarator: (qualified_identifier name: (operator_name) @name)))) @definition.method\n\n; Destructors (destructor_name is distinct from identifier in tree-sitter-cpp)\n(function_definition declarator: (function_declarator declarator: (qualified_identifier name: (destructor_name) @name))) @definition.method\n\n; Function declarations / prototypes (common in headers)\n(declaration declarator: (function_declarator declarator: (identifier) @name)) @definition.function\n(declaration declarator: (function_declarator declarator: (operator_name) @name)) @definition.function\n(declaration declarator: (pointer_declarator declarator: (function_declarator declarator: (identifier) @name))) @definition.function\n(declaration declarator: (reference_declarator (function_declarator declarator: (operator_name) @name))) @definition.function\n\n; Class/struct data member fields (Address address; int count;)\n; Uses field_identifier to exclude method declarations (which use function_declarator)\n(field_declaration\n declarator: (field_identifier) @name) @definition.property\n\n; Pointer member fields (Address* address;)\n(field_declaration\n declarator: (pointer_declarator\n declarator: (field_identifier) @name)) @definition.property\n\n; Reference member fields (Address& address;)\n(field_declaration\n declarator: (reference_declarator\n (field_identifier) @name)) @definition.property\n\n; Inline class method declarations (inside class body, no body: void save();)\n; tree-sitter-cpp uses field_identifier (not identifier) for names inside class bodies\n(field_declaration declarator: (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name)) @definition.method\n\n; Inline class method declarations returning a pointer (User* lookup();)\n(field_declaration declarator: (pointer_declarator declarator: (function_declarator declarator: [(field_identifier) (identifier)] @name))) @definition.method\n\n; Inline class method declarations returning a reference (User& lookup();)\n(field_declaration declarator: (reference_declarator (function_declarator declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method\n\n; Inline class method definitions (inside class body, with body: void Foo() { ... })\n(field_declaration_list\n (function_definition\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name) (destructor_name)] @name)) @definition.method)\n\n; Inline class methods returning a pointer type (User* lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (pointer_declarator\n declarator: (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Inline class methods returning a reference type (User& lookup(int id) { ... })\n(field_declaration_list\n (function_definition\n declarator: (reference_declarator\n (function_declarator\n declarator: [(field_identifier) (identifier) (operator_name)] @name))) @definition.method)\n\n; Templates\n(template_declaration (class_specifier name: (type_identifier) @name)) @definition.template\n(template_declaration\n (class_specifier\n name: (template_type\n (type_identifier) @name\n (template_argument_list) @template-arguments))) @definition.template\n(template_declaration (function_definition declarator: (function_declarator declarator: (identifier) @name))) @definition.template\n\n; Includes\n(preproc_include path: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (qualified_identifier name: (identifier) @call.name)) @call\n(call_expression function: (template_function name: (identifier) @call.name)) @call\n(binary_expression operator: \"+\" @call.name) @call\n(binary_expression operator: \"<<\" @call.name) @call\n\n; Constructor calls: new User()\n(new_expression type: (type_identifier) @call.name) @call\n\n; Variable declarations: int x = 5; or auto x = 5;\n(declaration\n declarator: (init_declarator\n declarator: (identifier) @name)) @definition.variable\n\n; Structured bindings: auto [a, b] = makePair(); (one @name per bound identifier)\n(declaration\n declarator: (init_declarator\n declarator: (structured_binding_declarator\n (identifier) @name))) @definition.variable\n\n; Structured bindings, reference form: auto& [x, y] = tup;\n(declaration\n declarator: (init_declarator\n declarator: (reference_declarator\n (structured_binding_declarator\n (identifier) @name)))) @definition.variable\n\n; Write access: obj.field = value\n(assignment_expression\n left: (field_expression\n argument: (_) @assignment.receiver\n field: (field_identifier) @assignment.property)\n right: (_)) @assignment\n\n";
|
|
@@ -738,10 +738,11 @@ export const PYTHON_QUERIES = `
|
|
|
738
738
|
`;
|
|
739
739
|
// Java queries - works with tree-sitter-java
|
|
740
740
|
export const JAVA_QUERIES = `
|
|
741
|
-
; Classes, Interfaces, Enums, Annotations
|
|
741
|
+
; Classes, Interfaces, Enums, Records, Annotations
|
|
742
742
|
(class_declaration name: (identifier) @name) @definition.class
|
|
743
743
|
(interface_declaration name: (identifier) @name) @definition.interface
|
|
744
744
|
(enum_declaration name: (identifier) @name) @definition.enum
|
|
745
|
+
(record_declaration name: (identifier) @name) @definition.record
|
|
745
746
|
(annotation_type_declaration name: (identifier) @name) @definition.annotation
|
|
746
747
|
|
|
747
748
|
; Anonymous class bodies: new Runnable() { ... } — no @name capture; the
|
|
@@ -519,6 +519,27 @@ export declare const queryFTS: (tableName: string, indexName: string, query: str
|
|
|
519
519
|
[key: string]: any;
|
|
520
520
|
}>>;
|
|
521
521
|
/**
|
|
522
|
-
*
|
|
522
|
+
* True for the two benign "nothing to drop" `DROP_FTS_INDEX` failures —
|
|
523
|
+
* both catalog/binder exceptions, LadybugDB's classes for "this name isn't
|
|
524
|
+
* bound to anything right now" (probe-verified end-to-end through
|
|
525
|
+
* `dropFTSIndex`'s real `conn.query()` path against @ladybugdb/core
|
|
526
|
+
* 0.18.x): the named index was never created (`Binder exception: Table <T>
|
|
527
|
+
* doesn't have an index with name <name>.`), or the FTS extension/function
|
|
528
|
+
* isn't registered at all (`Catalog exception: function DROP_FTS_INDEX is
|
|
529
|
+
* not defined...`). A real engine failure — e.g. the `Runtime exception:
|
|
530
|
+
* FTS index '<name>' is inconsistent: ...` class from #2589 — is a
|
|
531
|
+
* DIFFERENT exception class (an execution-time failure, not a catalog/bind
|
|
532
|
+
* lookup miss), so this returns false for it. Anchored to the START of the
|
|
533
|
+
* message (not a bare substring search): every probed LadybugDB error leads
|
|
534
|
+
* with its exception class, and anchoring means a future message that merely
|
|
535
|
+
* mentions "Binder exception" or "Catalog exception" further in in the body
|
|
536
|
+
* of an otherwise-genuine failure can't be misclassified as benign. Pure
|
|
537
|
+
* string logic so it is unit-testable without a native LadybugDB connection.
|
|
538
|
+
*/
|
|
539
|
+
export declare const isBenignDropFtsIndexError: (message: string) => boolean;
|
|
540
|
+
/**
|
|
541
|
+
* Drop an FTS index. Tolerates only {@link isBenignDropFtsIndexError} —
|
|
542
|
+
* anything else rethrows instead of being silently masked, which previously
|
|
543
|
+
* let a corrupted index persist across analyze runs undetected.
|
|
523
544
|
*/
|
|
524
545
|
export declare const dropFTSIndex: (tableName: string, indexName: string) => Promise<void>;
|
|
@@ -2576,7 +2576,28 @@ export const queryFTS = async (tableName, indexName, query, limit = 20, conjunct
|
|
|
2576
2576
|
}
|
|
2577
2577
|
};
|
|
2578
2578
|
/**
|
|
2579
|
-
*
|
|
2579
|
+
* True for the two benign "nothing to drop" `DROP_FTS_INDEX` failures —
|
|
2580
|
+
* both catalog/binder exceptions, LadybugDB's classes for "this name isn't
|
|
2581
|
+
* bound to anything right now" (probe-verified end-to-end through
|
|
2582
|
+
* `dropFTSIndex`'s real `conn.query()` path against @ladybugdb/core
|
|
2583
|
+
* 0.18.x): the named index was never created (`Binder exception: Table <T>
|
|
2584
|
+
* doesn't have an index with name <name>.`), or the FTS extension/function
|
|
2585
|
+
* isn't registered at all (`Catalog exception: function DROP_FTS_INDEX is
|
|
2586
|
+
* not defined...`). A real engine failure — e.g. the `Runtime exception:
|
|
2587
|
+
* FTS index '<name>' is inconsistent: ...` class from #2589 — is a
|
|
2588
|
+
* DIFFERENT exception class (an execution-time failure, not a catalog/bind
|
|
2589
|
+
* lookup miss), so this returns false for it. Anchored to the START of the
|
|
2590
|
+
* message (not a bare substring search): every probed LadybugDB error leads
|
|
2591
|
+
* with its exception class, and anchoring means a future message that merely
|
|
2592
|
+
* mentions "Binder exception" or "Catalog exception" further in in the body
|
|
2593
|
+
* of an otherwise-genuine failure can't be misclassified as benign. Pure
|
|
2594
|
+
* string logic so it is unit-testable without a native LadybugDB connection.
|
|
2595
|
+
*/
|
|
2596
|
+
export const isBenignDropFtsIndexError = (message) => message.startsWith('Binder exception:') || message.startsWith('Catalog exception:');
|
|
2597
|
+
/**
|
|
2598
|
+
* Drop an FTS index. Tolerates only {@link isBenignDropFtsIndexError} —
|
|
2599
|
+
* anything else rethrows instead of being silently masked, which previously
|
|
2600
|
+
* let a corrupted index persist across analyze runs undetected.
|
|
2580
2601
|
*/
|
|
2581
2602
|
export const dropFTSIndex = async (tableName, indexName) => {
|
|
2582
2603
|
if (!conn) {
|
|
@@ -2585,8 +2606,11 @@ export const dropFTSIndex = async (tableName, indexName) => {
|
|
|
2585
2606
|
try {
|
|
2586
2607
|
await queryAndDrain(conn, `CALL DROP_FTS_INDEX('${tableName}', '${indexName}')`);
|
|
2587
2608
|
}
|
|
2588
|
-
catch {
|
|
2589
|
-
|
|
2609
|
+
catch (e) {
|
|
2610
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2611
|
+
if (!isBenignDropFtsIndexError(msg)) {
|
|
2612
|
+
throw e;
|
|
2613
|
+
}
|
|
2590
2614
|
}
|
|
2591
2615
|
finally {
|
|
2592
2616
|
ensuredFTSIndexes.delete(ftsIndexKey(tableName, indexName));
|
package/dist/core/run-analyze.js
CHANGED
|
@@ -15,7 +15,7 @@ import { resetDegradedParseCounter } from './tree-sitter/safe-parse.js';
|
|
|
15
15
|
import { initLbug, loadGraphToLbug, getLbugStats, executeQuery, executeWithReusedStatement, closeLbug, closeLbugBeforeExit, loadCachedEmbeddings, deleteNodesForFiles, deleteAllCommunitiesAndProcesses, deleteAllInterprocTaintPaths, deleteAllCallSummaries, deleteAllInjects, queryImportersBatch, loadFTSExtension, wipeLbugDbFiles, LbugWipeError, DELETE_FILES_CHUNK_SIZE, } from './lbug/lbug-adapter.js';
|
|
16
16
|
import { estimateBufferPool, setBufferPoolSizeHint } from './lbug/lbug-config.js';
|
|
17
17
|
import { escapeCypherString } from './lbug/cypher-escape.js';
|
|
18
|
-
import { buildSearchIndexesOrDegrade, createSearchFTSIndexes, initialiseSearchFTSStemmer, verifySearchFTSIndexes, } from './search/fts-indexes.js';
|
|
18
|
+
import { buildSearchIndexesOrDegrade, createSearchFTSIndexes, dropSearchFTSIndexes, initialiseSearchFTSStemmer, verifySearchFTSIndexes, } from './search/fts-indexes.js';
|
|
19
19
|
import { cjkSegmentationModeMismatch, getSearchFTSCjkSegmentation, initialiseSearchFTSCjkSegmentation, } from './search/cjk-segmentation.js';
|
|
20
20
|
import { getExtensionCapabilities, resolveAnalyzeInstallPolicy } from './lbug/extension-loader.js';
|
|
21
21
|
import { diagnoseExtensionLoad } from './lbug/extension-load-error.js';
|
|
@@ -1199,7 +1199,20 @@ export async function runFullAnalysis(repoPath, options, callbacks, runnerIdenti
|
|
|
1199
1199
|
});
|
|
1200
1200
|
}
|
|
1201
1201
|
else {
|
|
1202
|
-
// 1a.
|
|
1202
|
+
// 1a. Drop every FTS index before touching a single row (#2589).
|
|
1203
|
+
// `deleteNodesForFiles` below DETACH DELETEs rows out of tables
|
|
1204
|
+
// that otherwise still carry the FTS index built at the end of
|
|
1205
|
+
// the PREVIOUS analyze run — Phase 3 doesn't drop+rebuild it
|
|
1206
|
+
// until well after this delete completes. LadybugDB's FTS
|
|
1207
|
+
// extension is not proven to survive DML against an indexed
|
|
1208
|
+
// table (its own docs never demonstrate it), and that ordering
|
|
1209
|
+
// is exactly what produced "FTS index 'file_fts' is
|
|
1210
|
+
// inconsistent: term is missing during delete". Dropping first
|
|
1211
|
+
// removes the hazard outright; Phase 3's createSearchFTSIndexes
|
|
1212
|
+
// rebuilds every index from the final row set regardless, so
|
|
1213
|
+
// this is a no-op on its own drop step there.
|
|
1214
|
+
await dropSearchFTSIndexes();
|
|
1215
|
+
// 1b. Remove the write set's existing rows — batched (#2409): one
|
|
1203
1216
|
// DETACH DELETE per table per 200-file chunk. The former per-file
|
|
1204
1217
|
// loop issued a count + delete per table per FILE — ~13k
|
|
1205
1218
|
// single-row write transactions on a ~700-file write set — which
|
|
@@ -24,6 +24,15 @@ export declare function initialiseSearchFTSStemmer(): string;
|
|
|
24
24
|
* tests) so validation always applies.
|
|
25
25
|
*/
|
|
26
26
|
export declare function getSearchFTSStemmer(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Drop every configured FTS index (no-op per index when absent or unloadable
|
|
29
|
+
* — `dropFTSIndex` tolerates both). Callable ahead of any DML that mutates an
|
|
30
|
+
* FTS-indexed table's rows: LadybugDB's FTS extension is not proven to
|
|
31
|
+
* survive a DETACH DELETE against a table that still carries a live index
|
|
32
|
+
* from a prior run (#2589) — dropping first removes that hazard entirely,
|
|
33
|
+
* regardless of whether it also fixed a specific native inconsistency.
|
|
34
|
+
*/
|
|
35
|
+
export declare function dropSearchFTSIndexes(): Promise<void>;
|
|
27
36
|
export declare function createSearchFTSIndexes(options?: CreateSearchFTSIndexesOptions): Promise<void>;
|
|
28
37
|
export declare function verifySearchFTSIndexes(executeQuery: (cypher: string) => Promise<unknown[]>): Promise<string[]>;
|
|
29
38
|
export interface BuildSearchIndexesResult {
|
|
@@ -103,6 +103,19 @@ export function initialiseSearchFTSStemmer() {
|
|
|
103
103
|
export function getSearchFTSStemmer() {
|
|
104
104
|
return resolvedStemmer ?? resolveFTSStemmer();
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Drop every configured FTS index (no-op per index when absent or unloadable
|
|
108
|
+
* — `dropFTSIndex` tolerates both). Callable ahead of any DML that mutates an
|
|
109
|
+
* FTS-indexed table's rows: LadybugDB's FTS extension is not proven to
|
|
110
|
+
* survive a DETACH DELETE against a table that still carries a live index
|
|
111
|
+
* from a prior run (#2589) — dropping first removes that hazard entirely,
|
|
112
|
+
* regardless of whether it also fixed a specific native inconsistency.
|
|
113
|
+
*/
|
|
114
|
+
export async function dropSearchFTSIndexes() {
|
|
115
|
+
for (const { table, indexName } of FTS_INDEXES) {
|
|
116
|
+
await dropFTSIndex(table, indexName);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
106
119
|
export async function createSearchFTSIndexes(options) {
|
|
107
120
|
const stemmer = getSearchFTSStemmer();
|
|
108
121
|
for (const { table, indexName, properties } of FTS_INDEXES) {
|
|
@@ -403,8 +403,16 @@ export interface RepoMeta {
|
|
|
403
403
|
* `E.hook` to `E$1.hook`, and nested-host anonymous names re-key
|
|
404
404
|
* (`EnumWrap$1` → `EnumWrap$Mode$1`). Same contract as v8: identities move
|
|
405
405
|
* on unchanged files; force a full re-analyze.
|
|
406
|
-
|
|
407
|
-
|
|
406
|
+
* v10: Java `record_declaration` now emits a first-class `Record` graph node
|
|
407
|
+
* (#2564): a record's container node was previously never created (JAVA_QUERIES
|
|
408
|
+
* had no capture for it), so its methods existed as ownerless Method nodes
|
|
409
|
+
* with no `HAS_METHOD` edge. The incremental write set only covers changed
|
|
410
|
+
* files — a top-up against a pre-v10 index would keep silently omitting the
|
|
411
|
+
* `Record` node and its `HAS_METHOD` edges for every unchanged record file
|
|
412
|
+
* (same v7 contract: new nodes/edges the incremental path would otherwise
|
|
413
|
+
* never backfill); force a full re-analyze instead.
|
|
414
|
+
*/
|
|
415
|
+
export declare const INCREMENTAL_SCHEMA_VERSION = 10;
|
|
408
416
|
export interface IndexedRepo {
|
|
409
417
|
repoPath: string;
|
|
410
418
|
storagePath: string;
|
|
@@ -124,8 +124,16 @@ export const cloneDirBelongsToEntry = (cloneDir, entryPath) => registryPathEqual
|
|
|
124
124
|
* `E.hook` to `E$1.hook`, and nested-host anonymous names re-key
|
|
125
125
|
* (`EnumWrap$1` → `EnumWrap$Mode$1`). Same contract as v8: identities move
|
|
126
126
|
* on unchanged files; force a full re-analyze.
|
|
127
|
+
* v10: Java `record_declaration` now emits a first-class `Record` graph node
|
|
128
|
+
* (#2564): a record's container node was previously never created (JAVA_QUERIES
|
|
129
|
+
* had no capture for it), so its methods existed as ownerless Method nodes
|
|
130
|
+
* with no `HAS_METHOD` edge. The incremental write set only covers changed
|
|
131
|
+
* files — a top-up against a pre-v10 index would keep silently omitting the
|
|
132
|
+
* `Record` node and its `HAS_METHOD` edges for every unchanged record file
|
|
133
|
+
* (same v7 contract: new nodes/edges the incremental path would otherwise
|
|
134
|
+
* never backfill); force a full re-analyze instead.
|
|
127
135
|
*/
|
|
128
|
-
export const INCREMENTAL_SCHEMA_VERSION =
|
|
136
|
+
export const INCREMENTAL_SCHEMA_VERSION = 10;
|
|
129
137
|
const GITNEXUS_DIR = '.gitnexus';
|
|
130
138
|
const GITNEXUS_EXCLUDE_ENTRY = `${GITNEXUS_DIR}/`;
|
|
131
139
|
export const INDEX_METADATA_FILE = 'gitnexus.json';
|
package/package.json
CHANGED