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.
Files changed (24) hide show
  1. package/dist/core/ingestion/call-processor.d.ts +3 -3
  2. package/dist/core/ingestion/call-processor.js +56 -63
  3. package/dist/core/ingestion/language-provider.d.ts +8 -0
  4. package/dist/core/ingestion/languages/swift.js +14 -0
  5. package/dist/core/ingestion/method-extractors/configs/swift.js +3 -4
  6. package/dist/core/ingestion/parsing-processor.js +5 -3
  7. package/dist/core/ingestion/type-extractors/swift.js +7 -4
  8. package/dist/core/ingestion/workers/parse-worker.js +5 -3
  9. package/hooks/claude/gitnexus-hook.cjs +11 -1
  10. package/package.json +3 -3
  11. package/scripts/build-tree-sitter-proto.cjs +1 -1
  12. package/vendor/tree-sitter-swift/LICENSE +21 -0
  13. package/vendor/tree-sitter-swift/README.md +139 -0
  14. package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
  15. package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
  16. package/vendor/tree-sitter-swift/package.json +28 -0
  17. package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
  18. package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
  19. package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
  20. package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
  21. package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
  22. package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
  23. package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
  24. 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 Swift/Kotlin implicit constructors (`User()` without `new`)
134
- * by delegating to {@link resolveStaticCall} when the tiered pool contains
135
- * class-like targets.
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 Swift/Kotlin class-target fast path)
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
- * Collapse Swift-extension duplicate Class/Struct candidates to the primary
1280
- * definition, preferring the shortest file path.
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
- const sorted = [...candidates].sort((a, b) => a.filePath.length - b.filePath.length);
1312
- return toResolveResult(sorted[0], tier);
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 Swift/Kotlin implicit constructors (`User()` without `new`)
1795
- * by delegating to {@link resolveStaticCall} when the tiered pool contains
1796
- * class-like targets.
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: Swift/Kotlin `User()` — free-form call targeting a
1820
- // class. Delegates to resolveStaticCall for O(1) class + constructor lookup.
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 C# records and Kotlin data classes reach
1825
- // the fast path.
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 (e.g. Kotlin `object`) propagates here automatically.
1831
- // The `dedupSwiftExtensionCandidates` helper used in the tail of this
1832
- // function deliberately uses a narrower literal `'Class' | 'Struct'` check
1833
- // Swift extensions only produce Class duplicates in practice, so Record
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: Swift/Kotlin constructor calls look like
1843
- // free function calls (no `new` keyword). If resolveStaticCall didn't
1844
- // match, re-filter with constructor form so CONSTRUCTOR_TARGET_TYPES
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 `dedupSwiftExtensionCandidates` below, which
1860
- // either picks the shortest-path primary or null-routes.
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
- // See `dedupSwiftExtensionCandidates` shared helper, single source of
1886
- // truth for the Swift-extension same-name collision heuristic.
1887
- const deduped = dedupSwiftExtensionCandidates(filteredCandidates, tiered.tier);
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 → two or more instantiable classes share the name (e.g.
2038
- // homonym classes across files with no import narrowing). Fall through
2039
- // to `return null` so the caller null-routes rather than guess.
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.6.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 0.6.0, parameters are direct children of function_declaration.
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
- // tree-sitter-swift 0.6.0 may use class_declaration for classes, structs, enums, extensions,
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 Method/Constructor IDs to disambiguate overloads.
416
- // Functions are not suffixed they don't overload by name in the same scope.
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' || nodeLabel === 'Constructor';
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
- const suffix = callee.lastNamedChild;
103
- if (receiver?.type === 'simple_identifier' && suffix?.text === 'init') {
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?.text === 'init') {
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 Method/Constructor IDs to disambiguate overloads.
1619
- // Functions are not suffixed they don't overload by name in the same scope.
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' || nodeLabel === 'Constructor';
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)) return 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.19",
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/patch-tree-sitter-swift.cjs && node scripts/build-tree-sitter-dart.cjs && node scripts/build-tree-sitter-proto.cjs",
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": "^0.6.0"
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 scripts/patch-tree-sitter-swift.cjs. Best-effort: if any
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
+ ![Parse rate badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/parse_rate)
14
+ [![Crates.io badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/crates_io_version)](https://crates.io/crates/tree-sitter-swift)
15
+ [![NPM badge](https://byob.yarr.is/alex-pinkus/tree-sitter-swift/npm_version)](https://www.npmjs.com/package/tree-sitter-swift)
16
+ [![Build](https://github.com/alex-pinkus/tree-sitter-swift/actions/workflows/top-repos.yml/badge.svg)](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,7 @@
1
+ const root = require("path").join(__dirname, "..", "..");
2
+
3
+ module.exports = require("node-gyp-build")(root);
4
+
5
+ try {
6
+ module.exports.nodeTypeInfo = require("../../src/node-types.json");
7
+ } catch (_) {}
@@ -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
+ }