gitnexus 1.6.4-rc.19 → 1.6.4-rc.20
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/call-processor.d.ts +3 -3
- package/dist/core/ingestion/call-processor.js +56 -63
- package/dist/core/ingestion/language-provider.d.ts +8 -0
- package/dist/core/ingestion/languages/swift.js +14 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +3 -4
- package/dist/core/ingestion/parsing-processor.js +5 -3
- package/dist/core/ingestion/type-extractors/swift.js +7 -4
- package/dist/core/ingestion/workers/parse-worker.js +5 -3
- package/hooks/claude/gitnexus-hook.cjs +11 -1
- package/package.json +3 -3
- package/scripts/build-tree-sitter-proto.cjs +1 -1
- package/vendor/tree-sitter-swift/LICENSE +21 -0
- package/vendor/tree-sitter-swift/README.md +139 -0
- package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-swift/package.json +28 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
- package/scripts/patch-tree-sitter-swift.cjs +0 -78
|
@@ -130,9 +130,9 @@ export declare const resolveMemberCall: (ownerType: string, methodName: string,
|
|
|
130
130
|
* resolution via `ctx.resolve()`.
|
|
131
131
|
*
|
|
132
132
|
* Used for `foo()`, `doStuff()` — unqualified calls with no receiver.
|
|
133
|
-
* Also handles
|
|
134
|
-
*
|
|
135
|
-
*
|
|
133
|
+
* Also handles implicit constructors (`User()` without `new`) by delegating
|
|
134
|
+
* to {@link resolveStaticCall} when the tiered pool contains class-like
|
|
135
|
+
* targets.
|
|
136
136
|
*
|
|
137
137
|
* {@link resolveCallTarget} delegates here for `callForm === 'free'`.
|
|
138
138
|
*
|
|
@@ -3,7 +3,7 @@ import { CLASS_TYPES, CALL_TARGET_TYPES, lookupMethodByOwnerWithMRO } from './mo
|
|
|
3
3
|
* DAG stage 4 fallback: used when `selectDispatch` is absent or returns null.
|
|
4
4
|
* Preserves pre-DAG dispatch semantics:
|
|
5
5
|
* - 'constructor' → constructor branch
|
|
6
|
-
* - 'free' → free branch (admits
|
|
6
|
+
* - 'free' → free branch (admits class-target fast path)
|
|
7
7
|
* - 'member' or undefined → owner-scoped branch
|
|
8
8
|
*
|
|
9
9
|
* `undefined` callForm MUST route through owner-scoped (not free) so bare
|
|
@@ -1275,41 +1275,19 @@ const disambiguateByOverloadOrArgTypes = (pool, overloadHints, preComputedArgTyp
|
|
|
1275
1275
|
return matchCandidatesByArgTypes(pool, preComputedArgTypes);
|
|
1276
1276
|
return null;
|
|
1277
1277
|
};
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
*
|
|
1282
|
-
* Swift extensions (`extension User { ... }` in a separate file) create
|
|
1283
|
-
* multiple `Class` nodes sharing the same symbol name — one for the primary
|
|
1284
|
-
* declaration and one per extension file. When overload disambiguation and
|
|
1285
|
-
* receiver narrowing both fail to converge on a single candidate, this
|
|
1286
|
-
* heuristic picks the primary definition based on the assumption that it
|
|
1287
|
-
* lives at the shortest file path (e.g. `User.swift` over `UserExtensions.swift`).
|
|
1288
|
-
*
|
|
1289
|
-
* Intentionally narrower than {@link INSTANTIABLE_CLASS_TYPES}: only `Class`
|
|
1290
|
-
* and `Struct` are considered, not `Record`. Swift extensions only produce
|
|
1291
|
-
* `Class` duplicates in practice, and C#/Kotlin records do not exhibit the
|
|
1292
|
-
* same multi-file-definition pattern, so widening this set risks accidental
|
|
1293
|
-
* dedup of legitimately distinct record types.
|
|
1294
|
-
*
|
|
1295
|
-
* Returns a `ResolveResult` when the heuristic fires, `null` when the
|
|
1296
|
-
* candidate pool does not match the shape (mixed types, non-Class/Struct
|
|
1297
|
-
* kinds, or `length <= 1`). Callers should fall through to their own null
|
|
1298
|
-
* return when this helper returns `null`.
|
|
1299
|
-
*
|
|
1300
|
-
* Used by `resolveFreeCall`. Having a single source of truth prevents
|
|
1301
|
-
* duplication if the heuristic is ever tuned.
|
|
1302
|
-
*/
|
|
1303
|
-
const dedupSwiftExtensionCandidates = (candidates, tier) => {
|
|
1304
|
-
if (candidates.length <= 1)
|
|
1305
|
-
return null;
|
|
1306
|
-
const allSameType = candidates.every((c) => c.type === candidates[0].type);
|
|
1307
|
-
if (!allSameType)
|
|
1308
|
-
return null;
|
|
1309
|
-
if (candidates[0].type !== 'Class' && candidates[0].type !== 'Struct')
|
|
1278
|
+
const orderProviderSameNameTypeCandidates = (candidates, typeName, filePath) => {
|
|
1279
|
+
const language = getLanguageFromFilename(filePath);
|
|
1280
|
+
if (language == null)
|
|
1310
1281
|
return null;
|
|
1311
|
-
|
|
1312
|
-
|
|
1282
|
+
return (getProvider(language).orderSameNameTypeCandidates?.({
|
|
1283
|
+
typeName,
|
|
1284
|
+
callSiteFilePath: filePath,
|
|
1285
|
+
candidates,
|
|
1286
|
+
}) ?? null);
|
|
1287
|
+
};
|
|
1288
|
+
const resolveProviderPrimaryTypeCandidate = (candidates, tier, typeName, filePath) => {
|
|
1289
|
+
const ordered = orderProviderSameNameTypeCandidates(candidates, typeName, filePath);
|
|
1290
|
+
return ordered && ordered.length > 0 ? toResolveResult(ordered[0], tier) : null;
|
|
1313
1291
|
};
|
|
1314
1292
|
/**
|
|
1315
1293
|
* Thin dispatcher that routes a call to the appropriate specialized resolver.
|
|
@@ -1742,6 +1720,25 @@ ancestryView) => {
|
|
|
1742
1720
|
break;
|
|
1743
1721
|
}
|
|
1744
1722
|
}
|
|
1723
|
+
if (!firstDef && !ambiguous) {
|
|
1724
|
+
const orderedTypeCandidates = orderProviderSameNameTypeCandidates(ctx.model.types.lookupClassByName(receiverTypeName), receiverTypeName, filePath);
|
|
1725
|
+
if (orderedTypeCandidates) {
|
|
1726
|
+
for (const candidate of orderedTypeCandidates) {
|
|
1727
|
+
const def = canWalkMRO
|
|
1728
|
+
? lookupMethodByOwnerWithMRO(candidate.nodeId, methodName, heritageMap, ctx.model, mroStrategy, argCount)
|
|
1729
|
+
: ctx.model.methods.lookupMethodByOwner(candidate.nodeId, methodName, argCount);
|
|
1730
|
+
if (!def)
|
|
1731
|
+
continue;
|
|
1732
|
+
if (!firstDef) {
|
|
1733
|
+
firstDef = def;
|
|
1734
|
+
}
|
|
1735
|
+
else if (def.nodeId !== firstDef.nodeId) {
|
|
1736
|
+
ambiguous = true;
|
|
1737
|
+
break;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1745
1742
|
if (!firstDef || ambiguous)
|
|
1746
1743
|
return undefined;
|
|
1747
1744
|
return { def: firstDef, tier: typeResolved.tier };
|
|
@@ -1791,9 +1788,9 @@ export const resolveMemberCall = (ownerType, methodName, currentFile, ctx, herit
|
|
|
1791
1788
|
* resolution via `ctx.resolve()`.
|
|
1792
1789
|
*
|
|
1793
1790
|
* Used for `foo()`, `doStuff()` — unqualified calls with no receiver.
|
|
1794
|
-
* Also handles
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1791
|
+
* Also handles implicit constructors (`User()` without `new`) by delegating
|
|
1792
|
+
* to {@link resolveStaticCall} when the tiered pool contains class-like
|
|
1793
|
+
* targets.
|
|
1797
1794
|
*
|
|
1798
1795
|
* {@link resolveCallTarget} delegates here for `callForm === 'free'`.
|
|
1799
1796
|
*
|
|
@@ -1816,33 +1813,30 @@ export const resolveFreeCall = (calledName, filePath, ctx, argCount, tieredOverr
|
|
|
1816
1813
|
if (!tiered)
|
|
1817
1814
|
return null;
|
|
1818
1815
|
let filteredCandidates = filterCallableCandidates(tiered.candidates, argCount, 'free');
|
|
1819
|
-
// Class-target fast path:
|
|
1820
|
-
//
|
|
1816
|
+
// Class-target fast path: free-form call targeting a class. Delegates to
|
|
1817
|
+
// resolveStaticCall for O(1) class + constructor lookup.
|
|
1821
1818
|
// The `.some()` trigger must stay aligned with `INSTANTIABLE_CLASS_TYPES` —
|
|
1822
1819
|
// any type admitted here that is not in that set will cause resolveStaticCall
|
|
1823
1820
|
// to return null, wasting two lookup passes per call. `Enum` is deliberately
|
|
1824
|
-
// excluded; `Record` is included so
|
|
1825
|
-
//
|
|
1821
|
+
// excluded; `Record` is included so record-like class targets reach the fast
|
|
1822
|
+
// path.
|
|
1826
1823
|
// Align with INSTANTIABLE_CLASS_TYPES by reusing the set directly rather
|
|
1827
1824
|
// than enumerating literal strings. This converts an invariant that was
|
|
1828
1825
|
// previously enforced by a comment ("keep this list aligned with
|
|
1829
1826
|
// INSTANTIABLE_CLASS_TYPES") into one enforced structurally — any future
|
|
1830
|
-
// extension of the set
|
|
1831
|
-
//
|
|
1832
|
-
//
|
|
1833
|
-
//
|
|
1834
|
-
// is excluded there by design. Do not collapse that helper into
|
|
1835
|
-
// INSTANTIABLE_CLASS_TYPES.
|
|
1827
|
+
// extension of the set propagates here automatically.
|
|
1828
|
+
// Language providers can still choose a primary same-name type candidate in
|
|
1829
|
+
// the tail of this function when their grammars index one logical type
|
|
1830
|
+
// multiple times.
|
|
1836
1831
|
const hasClassTarget = filteredCandidates.length === 0 &&
|
|
1837
1832
|
tiered.candidates.some((c) => INSTANTIABLE_CLASS_TYPES.has(c.type));
|
|
1838
1833
|
if (hasClassTarget) {
|
|
1839
1834
|
const staticResult = resolveStaticCall(calledName, filePath, ctx, argCount, tiered);
|
|
1840
1835
|
if (staticResult)
|
|
1841
1836
|
return staticResult;
|
|
1842
|
-
// Retry with constructor form
|
|
1843
|
-
// free function calls
|
|
1844
|
-
//
|
|
1845
|
-
// applies.
|
|
1837
|
+
// Retry with constructor form for languages whose constructor calls look
|
|
1838
|
+
// like free function calls. If resolveStaticCall didn't match, re-filter
|
|
1839
|
+
// with constructor form so CONSTRUCTOR_TARGET_TYPES applies.
|
|
1846
1840
|
//
|
|
1847
1841
|
// The retry fires for every null return from `resolveStaticCall`, which
|
|
1848
1842
|
// can happen for three distinct reasons — all three are handled below:
|
|
@@ -1856,9 +1850,8 @@ export const resolveFreeCall = (calledName, filePath, ctx, argCount, tieredOverr
|
|
|
1856
1850
|
// (b) Homonym ambiguity — two or more instantiable class candidates
|
|
1857
1851
|
// share the name (e.g. `User` in two files, same tier). The
|
|
1858
1852
|
// retry repopulates `filteredCandidates` with both Classes and
|
|
1859
|
-
// they flow into
|
|
1860
|
-
//
|
|
1861
|
-
// Covered by the R7 Swift-extension dedup test.
|
|
1853
|
+
// they flow into the provider same-name candidate hook below, which
|
|
1854
|
+
// can pick a primary definition or null-route.
|
|
1862
1855
|
//
|
|
1863
1856
|
// (c) `resolveStaticCall` step 4 bailed because the tiered pool
|
|
1864
1857
|
// contains ownerless `Constructor` nodes (some extractors emit
|
|
@@ -1882,11 +1875,9 @@ export const resolveFreeCall = (calledName, filePath, ctx, argCount, tieredOverr
|
|
|
1882
1875
|
return toResolveResult(disambiguated, tiered.tier);
|
|
1883
1876
|
}
|
|
1884
1877
|
if (filteredCandidates.length !== 1) {
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
if (deduped)
|
|
1889
|
-
return deduped;
|
|
1878
|
+
const primary = resolveProviderPrimaryTypeCandidate(filteredCandidates, tiered.tier, calledName, filePath);
|
|
1879
|
+
if (primary)
|
|
1880
|
+
return primary;
|
|
1890
1881
|
return null;
|
|
1891
1882
|
}
|
|
1892
1883
|
return toResolveResult(filteredCandidates[0], tiered.tier);
|
|
@@ -2034,9 +2025,11 @@ export const resolveStaticCall = (className, currentFile, ctx, argCount, tieredO
|
|
|
2034
2025
|
// Interface / Trait / Impl). Null-route via the fall-through `return
|
|
2035
2026
|
// null` — this is the dominant Codex-fix case.
|
|
2036
2027
|
// length === 1 → a single instantiable candidate remains, return it.
|
|
2037
|
-
// length > 1 →
|
|
2038
|
-
//
|
|
2039
|
-
|
|
2028
|
+
// length > 1 → let the call-site provider choose a primary when it can
|
|
2029
|
+
// prove the candidates are one logical type; otherwise null-route.
|
|
2030
|
+
const primary = resolveProviderPrimaryTypeCandidate(instantiableCandidates, typeResolved.tier, className, currentFile);
|
|
2031
|
+
if (primary)
|
|
2032
|
+
return primary;
|
|
2040
2033
|
if (instantiableCandidates.length === 1) {
|
|
2041
2034
|
return toResolveResult(instantiableCandidates[0], typeResolved.tier);
|
|
2042
2035
|
}
|
|
@@ -382,6 +382,14 @@ interface LanguageProviderConfig {
|
|
|
382
382
|
* else treats as `'free'`).
|
|
383
383
|
*/
|
|
384
384
|
readonly classifyCallForm?: (captures: CaptureMatch, enclosingScope: Scope) => 'free' | 'member' | 'constructor' | 'index';
|
|
385
|
+
/** Order same-name type candidates when a language can index multiple
|
|
386
|
+
* definitions for one logical type. Return null to keep shared ambiguity
|
|
387
|
+
* handling. */
|
|
388
|
+
readonly orderSameNameTypeCandidates?: (params: {
|
|
389
|
+
readonly typeName: string;
|
|
390
|
+
readonly callSiteFilePath: string;
|
|
391
|
+
readonly candidates: readonly SymbolDefinition[];
|
|
392
|
+
}) => readonly SymbolDefinition[] | null;
|
|
385
393
|
/**
|
|
386
394
|
* Is this callable definition compatible with the given call-site arity?
|
|
387
395
|
* Language-specific rules: Python `*args`/`**kwargs`/defaults, JS default
|
|
@@ -112,6 +112,19 @@ const swiftExtractFunctionName = (node) => {
|
|
|
112
112
|
return { funcName: 'deinit', label: 'Constructor' };
|
|
113
113
|
return null; // fall through to generic
|
|
114
114
|
};
|
|
115
|
+
const orderSwiftSameNameTypeCandidates = ({ callSiteFilePath, candidates, }) => {
|
|
116
|
+
if (!callSiteFilePath.endsWith('.swift'))
|
|
117
|
+
return null;
|
|
118
|
+
if (candidates.length <= 1)
|
|
119
|
+
return null;
|
|
120
|
+
if (!candidates.every((c) => c.type === candidates[0].type))
|
|
121
|
+
return null;
|
|
122
|
+
if (candidates[0].type !== 'Class' && candidates[0].type !== 'Struct')
|
|
123
|
+
return null;
|
|
124
|
+
if (!candidates.every((c) => c.filePath.endsWith('.swift')))
|
|
125
|
+
return null;
|
|
126
|
+
return [...candidates].sort((a, b) => a.filePath.length - b.filePath.length || a.filePath.localeCompare(b.filePath));
|
|
127
|
+
};
|
|
115
128
|
const BUILT_INS = new Set([
|
|
116
129
|
'print',
|
|
117
130
|
'debugPrint',
|
|
@@ -240,5 +253,6 @@ export const swiftProvider = defineLanguage({
|
|
|
240
253
|
classExtractor: createClassExtractor(swiftClassConfig),
|
|
241
254
|
heritageExtractor: createHeritageExtractor(SupportedLanguages.Swift),
|
|
242
255
|
implicitImportWirer: wireSwiftImplicitImports,
|
|
256
|
+
orderSameNameTypeCandidates: orderSwiftSameNameTypeCandidates,
|
|
243
257
|
builtInNames: BUILT_INS,
|
|
244
258
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// gitnexus/src/core/ingestion/method-extractors/configs/swift.ts
|
|
2
|
-
// Verified against tree-sitter-swift 0.
|
|
2
|
+
// Verified against tree-sitter-swift 0.7.x
|
|
3
3
|
import { SupportedLanguages } from '../../../../_shared/index.js';
|
|
4
4
|
import { findVisibility, hasKeyword, hasModifier } from '../../field-extractors/configs/helpers.js';
|
|
5
5
|
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
|
|
@@ -97,7 +97,7 @@ function extractSwiftReturnType(node) {
|
|
|
97
97
|
*/
|
|
98
98
|
function extractSwiftParameters(node) {
|
|
99
99
|
const params = [];
|
|
100
|
-
// In tree-sitter-swift
|
|
100
|
+
// In tree-sitter-swift, parameters are direct children of function_declaration.
|
|
101
101
|
// Default value tokens ('=', literal) are siblings of the parameter node at the
|
|
102
102
|
// function_declaration level, not children of the parameter node.
|
|
103
103
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -242,8 +242,7 @@ function extractSwiftAnnotations(node) {
|
|
|
242
242
|
// ---------------------------------------------------------------------------
|
|
243
243
|
export const swiftMethodConfig = {
|
|
244
244
|
language: SupportedLanguages.Swift,
|
|
245
|
-
//
|
|
246
|
-
// and actors — but this cannot be verified until the grammar installs on Node 22+.
|
|
245
|
+
// Keep this conservative until Swift type-shape coverage is expanded.
|
|
247
246
|
// TODO: Verify struct_declaration, enum_declaration, extension_declaration, actor_declaration
|
|
248
247
|
// node types once tree-sitter-swift loads on Node 22, and add them here if they are distinct.
|
|
249
248
|
// protocol_declaration is a separate, confirmed node type.
|
|
@@ -412,10 +412,12 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
|
|
|
412
412
|
}
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
|
-
// Append #<paramCount> to
|
|
416
|
-
//
|
|
415
|
+
// Append #<paramCount> to owned callable IDs to disambiguate overloads.
|
|
416
|
+
// Top-level Function IDs stay stable; functions inside an owner may overload.
|
|
417
417
|
// When same-arity collisions exist, append ~type1,type2 for further disambiguation.
|
|
418
|
-
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
418
|
+
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
419
|
+
nodeLabel === 'Constructor' ||
|
|
420
|
+
(nodeLabel === 'Function' && enclosingClassId !== null);
|
|
419
421
|
let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
|
|
420
422
|
if (arityTag && seqDefMethods && seqDefMethodInfo && seqClassNodeId !== undefined) {
|
|
421
423
|
// Use cached method map + collision groups (built once per class, not per method)
|
|
@@ -21,6 +21,9 @@ function unwrapSwiftExpression(node) {
|
|
|
21
21
|
}
|
|
22
22
|
return node;
|
|
23
23
|
}
|
|
24
|
+
function swiftNavigationSuffixName(node) {
|
|
25
|
+
return node?.type === 'navigation_suffix' ? node.lastNamedChild?.text : node?.text;
|
|
26
|
+
}
|
|
24
27
|
/** Swift: let x: Foo = ... */
|
|
25
28
|
const extractDeclaration = (node, env) => {
|
|
26
29
|
// Swift property_declaration has pattern and type_annotation
|
|
@@ -99,8 +102,8 @@ const extractInitializer = (node, env, classNames) => {
|
|
|
99
102
|
// Explicit init: User.init(name: "alice") — navigation_expression with .init suffix
|
|
100
103
|
if (callee.type === 'navigation_expression') {
|
|
101
104
|
const receiver = callee.firstNamedChild;
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
if (receiver?.type === 'simple_identifier' &&
|
|
106
|
+
swiftNavigationSuffixName(callee.lastNamedChild) === 'init') {
|
|
104
107
|
const calleeName = receiver.text;
|
|
105
108
|
if (calleeName && classNames.has(calleeName)) {
|
|
106
109
|
env.set(varName, calleeName);
|
|
@@ -114,7 +117,7 @@ const scanConstructorBinding = (node) => {
|
|
|
114
117
|
return undefined;
|
|
115
118
|
if (hasTypeAnnotation(node))
|
|
116
119
|
return undefined;
|
|
117
|
-
const pattern = node.childForFieldName('pattern');
|
|
120
|
+
const pattern = node.childForFieldName('pattern') ?? findChild(node, 'pattern');
|
|
118
121
|
if (!pattern)
|
|
119
122
|
return undefined;
|
|
120
123
|
const varName = pattern.text;
|
|
@@ -147,7 +150,7 @@ const scanConstructorBinding = (node) => {
|
|
|
147
150
|
if (callee.type === 'navigation_expression') {
|
|
148
151
|
const receiver = callee.firstNamedChild;
|
|
149
152
|
const suffix = callee.lastNamedChild;
|
|
150
|
-
if (receiver?.type === 'simple_identifier' && suffix
|
|
153
|
+
if (receiver?.type === 'simple_identifier' && swiftNavigationSuffixName(suffix) === 'init') {
|
|
151
154
|
return { varName, calleeName: receiver.text };
|
|
152
155
|
}
|
|
153
156
|
// General qualified call: service.getUser() → extract method name.
|
|
@@ -1615,10 +1615,12 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1615
1615
|
}
|
|
1616
1616
|
}
|
|
1617
1617
|
}
|
|
1618
|
-
// Append #<paramCount> to
|
|
1619
|
-
//
|
|
1618
|
+
// Append #<paramCount> to owned callable IDs to disambiguate overloads.
|
|
1619
|
+
// Top-level Function IDs stay stable; functions inside an owner may overload.
|
|
1620
1620
|
// When same-arity collisions exist, append ~type1,type2 for further disambiguation.
|
|
1621
|
-
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
1621
|
+
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
1622
|
+
nodeLabel === 'Constructor' ||
|
|
1623
|
+
(nodeLabel === 'Function' && enclosingClassId !== null);
|
|
1622
1624
|
let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
|
|
1623
1625
|
if (arityTag && defMethodMap && defMethodInfo) {
|
|
1624
1626
|
const groups = buildCollisionGroups(defMethodMap);
|
|
@@ -31,11 +31,21 @@ function readInput() {
|
|
|
31
31
|
* Find the .gitnexus directory by walking up from startDir.
|
|
32
32
|
* Returns the path to .gitnexus/ or null if not found.
|
|
33
33
|
*/
|
|
34
|
+
function isGlobalRegistryDir(candidate) {
|
|
35
|
+
if (fs.existsSync(path.join(candidate, 'meta.json'))) return false;
|
|
36
|
+
return (
|
|
37
|
+
fs.existsSync(path.join(candidate, 'registry.json')) ||
|
|
38
|
+
fs.existsSync(path.join(candidate, 'repos'))
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
function findGitNexusDir(startDir) {
|
|
35
43
|
let dir = startDir || process.cwd();
|
|
36
44
|
for (let i = 0; i < 5; i++) {
|
|
37
45
|
const candidate = path.join(dir, '.gitnexus');
|
|
38
|
-
if (fs.existsSync(candidate))
|
|
46
|
+
if (fs.existsSync(candidate)) {
|
|
47
|
+
if (!isGlobalRegistryDir(candidate)) return candidate;
|
|
48
|
+
}
|
|
39
49
|
const parent = path.dirname(dir);
|
|
40
50
|
if (parent === dir) break;
|
|
41
51
|
dir = parent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitnexus",
|
|
3
|
-
"version": "1.6.4-rc.
|
|
3
|
+
"version": "1.6.4-rc.20",
|
|
4
4
|
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
|
5
5
|
"author": "Abhigyan Patwari",
|
|
6
6
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"test:integration": "vitest run test/integration",
|
|
48
48
|
"test:watch": "vitest",
|
|
49
49
|
"test:coverage": "vitest run --coverage",
|
|
50
|
-
"postinstall": "node scripts/
|
|
50
|
+
"postinstall": "node scripts/build-tree-sitter-dart.cjs && node scripts/build-tree-sitter-proto.cjs",
|
|
51
51
|
"prepare": "node scripts/build.js",
|
|
52
52
|
"prepack": "node scripts/build.js"
|
|
53
53
|
},
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"tree-sitter-dart": "file:./vendor/tree-sitter-dart",
|
|
92
92
|
"tree-sitter-kotlin": "^0.3.8",
|
|
93
93
|
"tree-sitter-proto": "file:./vendor/tree-sitter-proto",
|
|
94
|
-
"tree-sitter-swift": "
|
|
94
|
+
"tree-sitter-swift": "file:./vendor/tree-sitter-swift"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@types/cli-progress": "^3.11.6",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `node_modules/tree-sitter-proto/build/Release/tree_sitter_proto_binding.node`
|
|
27
27
|
* — under npm-managed territory, safe on upgrade.
|
|
28
28
|
*
|
|
29
|
-
* Mirrors
|
|
29
|
+
* Mirrors the tree-sitter-dart build helper. Best-effort: if any
|
|
30
30
|
* precondition fails (optional dep absent, no toolchain, --ignore-scripts),
|
|
31
31
|
* warn and exit 0 so gitnexus install still succeeds.
|
|
32
32
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 alex-pinkus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
## GitNexus vendor notice
|
|
2
|
+
|
|
3
|
+
This directory is a GitNexus-managed vendored copy of the official
|
|
4
|
+
`tree-sitter-swift@0.7.1` npm runtime package, including its official native
|
|
5
|
+
prebuilds. GitNexus keeps the top-level `tree-sitter` dependency pinned to
|
|
6
|
+
`^0.21.1` until the broader parser runtime upgrade is handled separately.
|
|
7
|
+
|
|
8
|
+
When updating this vendor package, replace it from an official
|
|
9
|
+
`tree-sitter-swift` npm release, keep the native `prebuilds/` artifacts, update
|
|
10
|
+
the `_vendoredBy` provenance fields in `package.json`, and verify the packed
|
|
11
|
+
GitNexus tarball can load `tree-sitter-swift`.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
[](https://crates.io/crates/tree-sitter-swift)
|
|
15
|
+
[](https://www.npmjs.com/package/tree-sitter-swift)
|
|
16
|
+
[](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml)
|
|
17
|
+
|
|
18
|
+
# tree-sitter-swift
|
|
19
|
+
|
|
20
|
+
This contains a [`tree-sitter`](https://tree-sitter.github.io/tree-sitter) grammar for the Swift programming language.
|
|
21
|
+
|
|
22
|
+
## Getting started
|
|
23
|
+
|
|
24
|
+
To use this parser to parse Swift code, you'll want to depend on either the Rust crate or the NPM package.
|
|
25
|
+
|
|
26
|
+
### Rust
|
|
27
|
+
|
|
28
|
+
To use the Rust crate, you'll add this to your `Cargo.toml`:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
tree-sitter = "0.23.0"
|
|
32
|
+
tree-sitter-swift = "=0.7.0"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Then you can use a `tree-sitter` parser with the language declared here:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
let mut parser = tree_sitter::Parser::new();
|
|
39
|
+
parser.set_language(tree_sitter_swift::language())?;
|
|
40
|
+
|
|
41
|
+
// ...
|
|
42
|
+
|
|
43
|
+
let tree = parser.parse(&my_source_code, None)
|
|
44
|
+
.ok_or_else(|| /* error handling code */)?;
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Javascript
|
|
48
|
+
|
|
49
|
+
To use this from NPM, you'll add similar dependencies to `package.json`:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
"dependencies: {
|
|
53
|
+
"tree-sitter-swift": "0.7.0",
|
|
54
|
+
"tree-sitter": "^0.22.1"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Your usage of the parser will look like:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
const Parser = require("tree-sitter");
|
|
62
|
+
const Swift = require("tree-sitter-swift");
|
|
63
|
+
|
|
64
|
+
const parser = new Parser();
|
|
65
|
+
parser.setLanguage(Swift);
|
|
66
|
+
|
|
67
|
+
// ...
|
|
68
|
+
|
|
69
|
+
const tree = parser.parse(mySourceCode);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Editing the grammar
|
|
73
|
+
|
|
74
|
+
With this package checked out, a common workflow for editing the grammar will look something like:
|
|
75
|
+
|
|
76
|
+
1. Make a change to `grammar.ts`.
|
|
77
|
+
2. Run `npm install && npm test` to see whether the change has had impact on existing parsing behavior. The default
|
|
78
|
+
`npm test` target requires `valgrind` to be installed; if you do not have it installed, and do not wish to, you can
|
|
79
|
+
substitute `tree-sitter test` directly.
|
|
80
|
+
3. Run `tree-sitter parse` on some real Swift codebase and see whether (or where) it fails.
|
|
81
|
+
4. Use any failures to create new corpus test cases.
|
|
82
|
+
|
|
83
|
+
## Contributions
|
|
84
|
+
|
|
85
|
+
All contributions to this repository are welcome.
|
|
86
|
+
|
|
87
|
+
If said contribution is to check generated files (e.g., `parser.c`) into the repository, be aware that your contribution will not be accepted. Make sure to read the [FAQ entry](https://github.com/alex-pinkus/tree-sitter-swift?tab=readme-ov-file#where-is-your-parserc) and the [prior](https://github.com/alex-pinkus/tree-sitter-swift/issues/362) [discussions](https://github.com/alex-pinkus/tree-sitter-swift/pull/315) and [compromises](https://github.com/alex-pinkus/tree-sitter-swift/issues/149) that have occurred already on this topic.
|
|
88
|
+
|
|
89
|
+
## Using tree-sitter-swift in Web Assembly
|
|
90
|
+
|
|
91
|
+
To use tree-sitter-swift as a language for the web bindings version tree-sitter, which will likely be a more modern version than the published node
|
|
92
|
+
module. [see](https://github.com/tree-sitter/tree-sitter/blob/master/lib/binding_web/README.md). Follow the instructions below
|
|
93
|
+
|
|
94
|
+
1. Install the node modules `npm install web-tree-sitter tree-sitter-swift`
|
|
95
|
+
2. Run the tree-sitter cli to create the wasm bundle
|
|
96
|
+
```sh
|
|
97
|
+
$ npx tree-sitter build-asm ./node_modules/tree-sitter
|
|
98
|
+
```
|
|
99
|
+
3. Boot tree-sitter wasm like this.
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
const Parser = require('web-tree-sitter');
|
|
103
|
+
async function run() {
|
|
104
|
+
//needs to happen first
|
|
105
|
+
await Parser.init();
|
|
106
|
+
//wait for the load of swift
|
|
107
|
+
const Swift = await Parser.Language.load('./tree-sitter-swift.wasm');
|
|
108
|
+
|
|
109
|
+
const parser = new Parser();
|
|
110
|
+
parser.setLanguage(Swift);
|
|
111
|
+
|
|
112
|
+
//Parse your swift code here.
|
|
113
|
+
const tree = parser.parse('print("Hello, World!")');
|
|
114
|
+
}
|
|
115
|
+
//if you want to run this
|
|
116
|
+
run().then(console.log, console.error);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Frequently asked questions
|
|
120
|
+
|
|
121
|
+
### Where is your `parser.c`?
|
|
122
|
+
|
|
123
|
+
This repository currently omits most of the code that is autogenerated during a build. This means, for instance, that
|
|
124
|
+
`grammar.json` and `parser.c` are both only available following a build. It also significantly reduces noise during
|
|
125
|
+
diffs.
|
|
126
|
+
|
|
127
|
+
The side benefit of not checking in `parser.c` is that you can guarantee backwards compatibility. Parsers generated by
|
|
128
|
+
the tree-sitter CLI aren't always backwards compatible. If you need a parser, generate it yourself using the CLI; all
|
|
129
|
+
the information to do so is available in this package. By doing that, you'll also know for sure that your parser version
|
|
130
|
+
and your library version are compatible.
|
|
131
|
+
|
|
132
|
+
If you need a `parser.c`, and you don't care about the tree-sitter version, but you don't have a local setup that would
|
|
133
|
+
allow you to obtain the parser, you can just download one from a recent workflow run in this package. To do so:
|
|
134
|
+
|
|
135
|
+
- Go to the [GitHub actions page](https://github.com/alex-pinkus/tree-sitter-swift/actions) for this
|
|
136
|
+
repository.
|
|
137
|
+
- Click on the "Publish `grammar.json` and `parser.c`" action for the appropriate commit.
|
|
138
|
+
- Go down to `Artifacts` and click on `generated-parser-src`. All the relevant parser files will be available in your
|
|
139
|
+
download.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
type BaseNode = {
|
|
2
|
+
type: string;
|
|
3
|
+
named: boolean;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type ChildNode = {
|
|
7
|
+
multiple: boolean;
|
|
8
|
+
required: boolean;
|
|
9
|
+
types: BaseNode[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type NodeInfo =
|
|
13
|
+
| (BaseNode & {
|
|
14
|
+
subtypes: BaseNode[];
|
|
15
|
+
})
|
|
16
|
+
| (BaseNode & {
|
|
17
|
+
fields: { [name: string]: ChildNode };
|
|
18
|
+
children: ChildNode[];
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
type Language = {
|
|
22
|
+
name: string;
|
|
23
|
+
language: unknown;
|
|
24
|
+
nodeTypeInfo: NodeInfo[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
declare const language: Language;
|
|
28
|
+
export = language;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tree-sitter-swift",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "A tree-sitter grammar for the Swift programming language",
|
|
5
|
+
"main": "bindings/node/index.js",
|
|
6
|
+
"types": "bindings/node/index.d.ts",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/alex-pinkus/tree-sitter-swift.git"
|
|
11
|
+
},
|
|
12
|
+
"_vendoredBy": "gitnexus - minimal runtime package copied from official tree-sitter-swift@0.7.1 (gitHead 88bfd19a89be9d0481b14566fb6160cccea2fe0a). Keeps upstream prebuilds while allowing GitNexus to stay on tree-sitter@0.21.1 until #858 is resolved.",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"install": "node-gyp-build"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"node-addon-api": "^8.0.0",
|
|
18
|
+
"node-gyp-build": "^4.8.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"tree-sitter": "^0.21.1 || ^0.22.1"
|
|
22
|
+
},
|
|
23
|
+
"peerDependenciesMeta": {
|
|
24
|
+
"tree-sitter": {
|
|
25
|
+
"optional": true
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|