gitnexus 1.6.13-rc.21 → 1.6.13-rc.22

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.
@@ -15,17 +15,21 @@ export function interpretSwiftImport(captures) {
15
15
  const sourceCap = captures['@import.source'];
16
16
  if (sourceCap === undefined)
17
17
  return null;
18
- // Swift imports are whole-module (wildcard semantics): `import Foundation`
19
- // brings the entire module into scope, no named members. The SPM target
20
- // (first dotted segment) is the resolution target; the full path is kept
21
- // as importedName for reference. `@testable` resolves identically to a
22
- // plain import (same module is visible in test scope).
23
18
  const source = sourceCap.text;
24
- const fullPath = captures['@import.name']?.text ?? source;
19
+ const name = captures['@import.name']?.text ?? source;
20
+ const kindText = captures['@import.kind']?.text;
21
+ if (kindText === 'reexport' || kindText === 'named') {
22
+ return {
23
+ kind: kindText,
24
+ localName: name,
25
+ importedName: name,
26
+ targetRaw: source,
27
+ };
28
+ }
25
29
  return {
26
30
  kind: 'namespace',
27
31
  localName: source,
28
- importedName: fullPath,
32
+ importedName: name,
29
33
  targetRaw: source,
30
34
  };
31
35
  }
@@ -37,14 +37,15 @@
37
37
  * Array where Element: Equatable`) are not narrowed — the `Self`
38
38
  * type of a protocol method resolves to the protocol, not the
39
39
  * conforming type.
40
- * 2. **Cross-module `import` resolution** is still directory-segment
41
- * based (`import Foo` → files under a `Foo/` dir); explicit imports do
42
- * not yet consult the SPM target map (follow-up, tracked under #1935).
43
- * Same-target visibility (the common case) IS SPM-target-subtree
44
- * accurate — handled by sibling augmentation grouped via
45
- * `groupSwiftFilesBySpmTarget`, not by explicit imports.
40
+ * 2. **Cross-module `import` resolution** uses a Package.swift
41
+ * declaration map when one is present, otherwise the directory-segment
42
+ * index minus well-known SDK module names (#2964). Same-target
43
+ * visibility (the common case) is SPM-target-subtree grouping via
44
+ * `groupSwiftFilesBySpmTarget`, not explicit imports.
46
45
  * 3. **Operator / subscript overloads** dispatch by name only.
47
- * 4. **`@_exported import` re-exports** are treated as plain imports.
46
+ * 4. **`@_exported import`** is `ParsedImport` `kind: 'reexport'` and
47
+ * in-repo modules are closed transitively at resolve time. `public
48
+ * import` is not a re-export.
48
49
  */
49
50
  import type { ScopeResolver } from '../../scope-resolution/contract/scope-resolver.js';
50
51
  declare const swiftScopeResolver: ScopeResolver;
@@ -37,14 +37,15 @@
37
37
  * Array where Element: Equatable`) are not narrowed — the `Self`
38
38
  * type of a protocol method resolves to the protocol, not the
39
39
  * conforming type.
40
- * 2. **Cross-module `import` resolution** is still directory-segment
41
- * based (`import Foo` → files under a `Foo/` dir); explicit imports do
42
- * not yet consult the SPM target map (follow-up, tracked under #1935).
43
- * Same-target visibility (the common case) IS SPM-target-subtree
44
- * accurate — handled by sibling augmentation grouped via
45
- * `groupSwiftFilesBySpmTarget`, not by explicit imports.
40
+ * 2. **Cross-module `import` resolution** uses a Package.swift
41
+ * declaration map when one is present, otherwise the directory-segment
42
+ * index minus well-known SDK module names (#2964). Same-target
43
+ * visibility (the common case) is SPM-target-subtree grouping via
44
+ * `groupSwiftFilesBySpmTarget`, not explicit imports.
46
45
  * 3. **Operator / subscript overloads** dispatch by name only.
47
- * 4. **`@_exported import` re-exports** are treated as plain imports.
46
+ * 4. **`@_exported import`** is `ParsedImport` `kind: 'reexport'` and
47
+ * in-repo modules are closed transitively at resolve time. `public
48
+ * import` is not a re-export.
48
49
  */
49
50
  import { SupportedLanguages } from '../../../../_shared/index.js';
50
51
  import { loadSwiftPackageConfig } from '../../language-config.js';
@@ -69,11 +70,17 @@ const swiftScopeResolver = {
69
70
  // the SPM target subtree, not the immediate directory. Mirrors
70
71
  // `goScopeResolver`'s `loadGoModulePath`.
71
72
  loadResolutionConfig: (repoPath) => loadSwiftPackageConfig(repoPath),
72
- resolveImportTarget: (targetRaw, fromFile, allFilePaths) => {
73
- const ws = { fromFile, allFilePaths };
74
- return resolveSwiftImportTarget(interpretSwiftImport({
75
- '@import.source': { name: '@import.source', text: targetRaw, range: ZERO_RANGE },
76
- }) ?? { kind: 'namespace', localName: targetRaw, importedName: targetRaw, targetRaw }, ws);
73
+ resolveImportTarget: (targetRaw, fromFile, allFilePaths, resolutionConfig, context) => {
74
+ const ws = {
75
+ fromFile,
76
+ allFilePaths,
77
+ resolutionConfig,
78
+ parsedFiles: context?.parsedFiles,
79
+ };
80
+ return resolveSwiftImportTarget(context?.parsedImport ??
81
+ interpretSwiftImport({
82
+ '@import.source': { name: '@import.source', text: targetRaw, range: ZERO_RANGE },
83
+ }) ?? { kind: 'namespace', localName: targetRaw, importedName: targetRaw, targetRaw }, ws);
77
84
  },
78
85
  // Swift shadowing: local declarations hide imports.
79
86
  mergeBindings: (existing, incoming) => [...swiftMergeBindings([...existing, ...incoming])],
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Well-known Apple / Swift SDK module names that must not bind to a
3
+ * same-named in-repo folder on the no-manifest path (#2964).
4
+ *
5
+ * Modeled on `CSHARP_EXTERNAL_ROOTS`. A Package.swift target that uses
6
+ * one of these names still wins — this set is only the inferred/null path.
7
+ */
8
+ export declare const SWIFT_SDK_MODULES: ReadonlySet<string>;
9
+ export declare function isSwiftSdkModule(name: string): boolean;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Well-known Apple / Swift SDK module names that must not bind to a
3
+ * same-named in-repo folder on the no-manifest path (#2964).
4
+ *
5
+ * Modeled on `CSHARP_EXTERNAL_ROOTS`. A Package.swift target that uses
6
+ * one of these names still wins — this set is only the inferred/null path.
7
+ */
8
+ export const SWIFT_SDK_MODULES = new Set([
9
+ 'Foundation',
10
+ 'UIKit',
11
+ 'SwiftUI',
12
+ 'AppKit',
13
+ 'Combine',
14
+ 'Dispatch',
15
+ 'Darwin',
16
+ 'ObjectiveC',
17
+ 'Swift',
18
+ 'CoreFoundation',
19
+ 'CoreData',
20
+ 'CoreGraphics',
21
+ 'XCTest',
22
+ 'Testing',
23
+ 'Observation',
24
+ 'os',
25
+ ]);
26
+ export function isSwiftSdkModule(name) {
27
+ return SWIFT_SDK_MODULES.has(name);
28
+ }
@@ -9,31 +9,26 @@
9
9
  * drops cross-directory same-module edges and can mis-resolve a
10
10
  * constructor call to a wrong same-simple-named type in another target.
11
11
  *
12
- * This module duplicates the legacy `groupSwiftFilesByTarget`
13
- * (`languages/swift.ts`) semantics **verbatim** so the registry-primary
14
- * path matches legacy SPM-subtree grouping without touching the legacy
15
- * pipeline (hard constraint: legacy stays byte-identical). The SPM target
16
- * map is threaded in via the `resolutionConfig` channel
12
+ * The SPM target map is threaded in via the `resolutionConfig` channel
17
13
  * (`loadSwiftPackageConfig` → `resolutionConfig` → these hooks); see
18
14
  * `scope-resolver.ts` and `scope-resolution/pipeline/run.ts`.
19
15
  *
20
- * NOTE: This intentionally differs from the import-config module's
21
- * leading-`startsWith` (`import-resolvers/configs/swift.ts`): that module
22
- * fans a file out to EVERY matching target (a nested file can belong to
23
- * multiple configured target dirs there), whereas legacy module grouping
24
- * assigns each file to the FIRST matching target only (legacy `break`s) —
25
- * one bucket per file. Do not copy the import-config behavior here.
16
+ * Path matching is the same segment-boundary rule as import-config
17
+ * (`fileMatchesSwiftTargetDir`). Grouping assigns each file to the FIRST
18
+ * matching target; import-config fans a file out to every matching target.
26
19
  */
20
+ export { coerceDeclaredSwiftTargets } from '../../language-config.js';
27
21
  /**
28
- * Group `items` by SPM target subtree, replicating legacy
29
- * `groupSwiftFilesByTarget` semantics exactly:
22
+ * Group `items` by SPM target subtree:
30
23
  *
31
24
  * - `targets` null/empty (no scanned source dir found) → ALL items go to
32
25
  * a single `__default__` bucket (single-Xcode-project assumption).
33
26
  * - Otherwise: a file matches a target when its normalized path either
34
- * starts with `<targetDir>/` (`indexOf === 0`) OR contains it at a `/`
35
- * boundary (`norm[idx - 1] === '/'`). Each file is assigned to the
36
- * FIRST matching target only (one bucket per file, no fan-out).
27
+ * starts with `<targetDir>/` or contains `/<targetDir>/` at a segment
28
+ * boundary. Using a segment-aware suffix search matters when an earlier,
29
+ * non-boundary occurrence of the same text appears in the path (#2931).
30
+ * - Each file is assigned to the FIRST matching target only (one bucket per
31
+ * file, no fan-out).
37
32
  * - Files matching no target fall into the `__default__` bucket.
38
33
  *
39
34
  * `targets` is `name → directory` (the `SwiftPackageConfig.targets` map).
@@ -49,3 +44,5 @@ export declare function groupSwiftFilesBySpmTarget<T>(items: readonly T[], getPa
49
44
  * `undefined`, or a config object whose `targets` is a `Map<string,string>`.
50
45
  */
51
46
  export declare function coerceSwiftTargets(resolutionConfig: unknown): ReadonlyMap<string, string> | null;
47
+ /** Segment-boundary membership used by grouping and declared import resolve. */
48
+ export declare function fileMatchesSwiftTargetDir(normalizedPath: string, targetDir: string): boolean;
@@ -9,32 +9,28 @@
9
9
  * drops cross-directory same-module edges and can mis-resolve a
10
10
  * constructor call to a wrong same-simple-named type in another target.
11
11
  *
12
- * This module duplicates the legacy `groupSwiftFilesByTarget`
13
- * (`languages/swift.ts`) semantics **verbatim** so the registry-primary
14
- * path matches legacy SPM-subtree grouping without touching the legacy
15
- * pipeline (hard constraint: legacy stays byte-identical). The SPM target
16
- * map is threaded in via the `resolutionConfig` channel
12
+ * The SPM target map is threaded in via the `resolutionConfig` channel
17
13
  * (`loadSwiftPackageConfig` → `resolutionConfig` → these hooks); see
18
14
  * `scope-resolver.ts` and `scope-resolution/pipeline/run.ts`.
19
15
  *
20
- * NOTE: This intentionally differs from the import-config module's
21
- * leading-`startsWith` (`import-resolvers/configs/swift.ts`): that module
22
- * fans a file out to EVERY matching target (a nested file can belong to
23
- * multiple configured target dirs there), whereas legacy module grouping
24
- * assigns each file to the FIRST matching target only (legacy `break`s) —
25
- * one bucket per file. Do not copy the import-config behavior here.
16
+ * Path matching is the same segment-boundary rule as import-config
17
+ * (`fileMatchesSwiftTargetDir`). Grouping assigns each file to the FIRST
18
+ * matching target; import-config fans a file out to every matching target.
26
19
  */
20
+ import { swiftDeclaredTargetPrefix } from '../../language-config.js';
21
+ export { coerceDeclaredSwiftTargets } from '../../language-config.js';
27
22
  const DEFAULT_TARGET = '__default__';
28
23
  /**
29
- * Group `items` by SPM target subtree, replicating legacy
30
- * `groupSwiftFilesByTarget` semantics exactly:
24
+ * Group `items` by SPM target subtree:
31
25
  *
32
26
  * - `targets` null/empty (no scanned source dir found) → ALL items go to
33
27
  * a single `__default__` bucket (single-Xcode-project assumption).
34
28
  * - Otherwise: a file matches a target when its normalized path either
35
- * starts with `<targetDir>/` (`indexOf === 0`) OR contains it at a `/`
36
- * boundary (`norm[idx - 1] === '/'`). Each file is assigned to the
37
- * FIRST matching target only (one bucket per file, no fan-out).
29
+ * starts with `<targetDir>/` or contains `/<targetDir>/` at a segment
30
+ * boundary. Using a segment-aware suffix search matters when an earlier,
31
+ * non-boundary occurrence of the same text appears in the path (#2931).
32
+ * - Each file is assigned to the FIRST matching target only (one bucket per
33
+ * file, no fan-out).
38
34
  * - Files matching no target fall into the `__default__` bucket.
39
35
  *
40
36
  * `targets` is `name → directory` (the `SwiftPackageConfig.targets` map).
@@ -44,10 +40,9 @@ export function groupSwiftFilesBySpmTarget(items, getPath, targets) {
44
40
  if (targets === null || targets.size === 0) {
45
41
  return new Map([[DEFAULT_TARGET, [...items]]]);
46
42
  }
47
- // Pre-convert target dirs to normalized prefix format once.
48
43
  const targetPrefixes = [...targets.entries()].map(([name, dir]) => ({
49
44
  name,
50
- prefix: dir.replace(/\\/g, '/') + '/',
45
+ prefix: swiftDeclaredTargetPrefix(dir),
51
46
  }));
52
47
  const groups = new Map();
53
48
  const defaultGroup = [];
@@ -56,8 +51,7 @@ export function groupSwiftFilesBySpmTarget(items, getPath, targets) {
56
51
  const normalized = rawPath.includes('\\') ? rawPath.replace(/\\/g, '/') : rawPath;
57
52
  let assigned = false;
58
53
  for (const { name, prefix } of targetPrefixes) {
59
- const idx = normalized.indexOf(prefix);
60
- if (idx === 0 || (idx > 0 && normalized[idx - 1] === '/')) {
54
+ if (pathMatchesTargetPrefix(normalized, prefix)) {
61
55
  let group = groups.get(name);
62
56
  if (group === undefined) {
63
57
  group = [];
@@ -91,3 +85,12 @@ export function coerceSwiftTargets(resolutionConfig) {
91
85
  }
92
86
  return null;
93
87
  }
88
+ function pathMatchesTargetPrefix(normalizedPath, prefix) {
89
+ if (prefix === '')
90
+ return true;
91
+ return normalizedPath.startsWith(prefix) || normalizedPath.includes(`/${prefix}`);
92
+ }
93
+ /** Segment-boundary membership used by grouping and declared import resolve. */
94
+ export function fileMatchesSwiftTargetDir(normalizedPath, targetDir) {
95
+ return pathMatchesTargetPrefix(normalizedPath, swiftDeclaredTargetPrefix(targetDir));
96
+ }
@@ -10,10 +10,13 @@
10
10
  * Module identity: Swift has no in-source `package X` marker. The SPM
11
11
  * target is a directory subtree (`Sources/<Target>/…`). Module membership
12
12
  * is threaded in via the SPM target map (`ctx.resolutionConfig` →
13
- * `coerceSwiftTargets`) and grouped by `groupSwiftFilesBySpmTarget`,
14
- * replicating legacy `wireSwiftImplicitImports`'s `groupSwiftFilesByTarget`:
15
- * files are grouped by SPM target subtree when a package config is present,
16
- * else ALL Swift files form one module (`__default__`,
13
+ * `coerceSwiftTargets`) and grouped by `groupSwiftFilesBySpmTarget`.
14
+ * The helper preserves the legacy `wireSwiftImplicitImports` bucketing
15
+ * contract for ordinary layouts (first target wins and unmatched files use
16
+ * `__default__`) but intentionally fixes #2931's repeated-prefix edge case.
17
+ * When a target map is present (declared Package.swift or inferred
18
+ * `Sources/*` folders), files are grouped by SPM target subtree;
19
+ * otherwise ALL Swift files form one module (`__default__`,
17
20
  * single-Xcode-project assumption). Every `.swift` file in the same target
18
21
  * sees its siblings' top-level defs.
19
22
  *
@@ -10,10 +10,13 @@
10
10
  * Module identity: Swift has no in-source `package X` marker. The SPM
11
11
  * target is a directory subtree (`Sources/<Target>/…`). Module membership
12
12
  * is threaded in via the SPM target map (`ctx.resolutionConfig` →
13
- * `coerceSwiftTargets`) and grouped by `groupSwiftFilesBySpmTarget`,
14
- * replicating legacy `wireSwiftImplicitImports`'s `groupSwiftFilesByTarget`:
15
- * files are grouped by SPM target subtree when a package config is present,
16
- * else ALL Swift files form one module (`__default__`,
13
+ * `coerceSwiftTargets`) and grouped by `groupSwiftFilesBySpmTarget`.
14
+ * The helper preserves the legacy `wireSwiftImplicitImports` bucketing
15
+ * contract for ordinary layouts (first target wins and unmatched files use
16
+ * `__default__`) but intentionally fixes #2931's repeated-prefix edge case.
17
+ * When a target map is present (declared Package.swift or inferred
18
+ * `Sources/*` folders), files are grouped by SPM target subtree;
19
+ * otherwise ALL Swift files form one module (`__default__`,
17
20
  * single-Xcode-project assumption). Every `.swift` file in the same target
18
21
  * sees its siblings' top-level defs.
19
22
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.13-rc.21",
3
+ "version": "1.6.13-rc.22",
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",