gitnexus 1.6.13-rc.21 → 1.6.13-rc.23
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/import-resolvers/configs/swift.d.ts +12 -9
- package/dist/core/ingestion/import-resolvers/configs/swift.js +35 -27
- package/dist/core/ingestion/language-config.d.ts +32 -0
- package/dist/core/ingestion/language-config.js +809 -7
- package/dist/core/ingestion/languages/swift/implicit-imports.d.ts +8 -5
- package/dist/core/ingestion/languages/swift/implicit-imports.js +14 -13
- package/dist/core/ingestion/languages/swift/import-decomposer.d.ts +9 -13
- package/dist/core/ingestion/languages/swift/import-decomposer.js +213 -23
- package/dist/core/ingestion/languages/swift/import-target.d.ts +9 -21
- package/dist/core/ingestion/languages/swift/import-target.js +140 -34
- package/dist/core/ingestion/languages/swift/interpret.js +11 -7
- package/dist/core/ingestion/languages/swift/scope-resolver.d.ts +8 -7
- package/dist/core/ingestion/languages/swift/scope-resolver.js +19 -12
- package/dist/core/ingestion/languages/swift/sdk-modules.d.ts +9 -0
- package/dist/core/ingestion/languages/swift/sdk-modules.js +28 -0
- package/dist/core/ingestion/languages/swift/target-grouping.d.ts +13 -16
- package/dist/core/ingestion/languages/swift/target-grouping.js +23 -20
- package/dist/core/ingestion/languages/swift/target-siblings.d.ts +7 -4
- package/dist/core/ingestion/languages/swift/target-siblings.js +7 -4
- package/dist/core/run-analyze.js +3 -0
- package/dist/storage/repo-manager.d.ts +7 -0
- package/dist/storage/repo-manager.js +15 -1
- package/package.json +1 -1
|
@@ -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
|
|
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:
|
|
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**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
|
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**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
|
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 = {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* fans a file out 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
|
|
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>/`
|
|
35
|
-
* boundary
|
|
36
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* fans a file out 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
|
|
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>/`
|
|
36
|
-
* boundary
|
|
37
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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/dist/core/run-analyze.js
CHANGED
|
@@ -949,6 +949,7 @@ async function runFullAnalysisInner(repoPath, options, callbacks, writeTarget, c
|
|
|
949
949
|
if (options.registryName) {
|
|
950
950
|
await registerRepo(repoPath, existingMeta, {
|
|
951
951
|
name: options.registryName,
|
|
952
|
+
onRename: (previousName, nextName) => log(`Registry name changed: "${previousName}" -> "${nextName}".`),
|
|
952
953
|
allowDuplicateName: options.allowDuplicateName,
|
|
953
954
|
branch: placement.branch,
|
|
954
955
|
storagePath,
|
|
@@ -1441,6 +1442,7 @@ async function runFullAnalysisInner(repoPath, options, callbacks, writeTarget, c
|
|
|
1441
1442
|
if (options.registryName) {
|
|
1442
1443
|
await registerRepo(repoPath, existingMeta, {
|
|
1443
1444
|
name: options.registryName,
|
|
1445
|
+
onRename: (previousName, nextName) => log(`Registry name changed: "${previousName}" -> "${nextName}".`),
|
|
1444
1446
|
allowDuplicateName: options.allowDuplicateName,
|
|
1445
1447
|
branch: placement.branch,
|
|
1446
1448
|
storagePath,
|
|
@@ -3638,6 +3640,7 @@ async function runFullAnalysisInner(repoPath, options, callbacks, writeTarget, c
|
|
|
3638
3640
|
// will look up (#979).
|
|
3639
3641
|
const projectName = await registerRepo(repoPath, meta, {
|
|
3640
3642
|
name: options.registryName,
|
|
3643
|
+
onRename: (previousName, nextName) => log(`Registry name changed: "${previousName}" -> "${nextName}".`),
|
|
3641
3644
|
allowDuplicateName: options.allowDuplicateName,
|
|
3642
3645
|
// Non-primary branch runs upsert into the entry's branches[]; the
|
|
3643
3646
|
// primary/flat run (placement.branch === undefined) refreshes the
|
|
@@ -258,6 +258,13 @@ export interface RegisterRepoOptions {
|
|
|
258
258
|
* re-analyses of the same path without `--name` preserve the alias.
|
|
259
259
|
*/
|
|
260
260
|
name?: string;
|
|
261
|
+
/**
|
|
262
|
+
* Best-effort notification after an explicit alias change has been committed
|
|
263
|
+
* to the registry. Invoked after the registry lock is released. Callback
|
|
264
|
+
* failures are ignored: reporting must not turn a successful registry write
|
|
265
|
+
* into an apparent transaction failure.
|
|
266
|
+
*/
|
|
267
|
+
onRename?: (previousName: string, nextName: string) => void | Promise<void>;
|
|
261
268
|
/**
|
|
262
269
|
* Allow two DIFFERENT repo paths to register under the same alias
|
|
263
270
|
* (#829). Mapped from the `--allow-duplicate-name` CLI flag.
|
|
@@ -944,9 +944,23 @@ const registerRepoUnlocked = async (repoPath, meta, opts) => {
|
|
|
944
944
|
fresh.push(merged);
|
|
945
945
|
}
|
|
946
946
|
await writeRegistry(fresh);
|
|
947
|
+
const rename = opts?.name !== undefined && freshExisting && freshExisting.name !== name
|
|
948
|
+
? { previousName: freshExisting.name, nextName: name }
|
|
949
|
+
: undefined;
|
|
950
|
+
return { name, ...(rename ? { rename } : {}) };
|
|
951
|
+
};
|
|
952
|
+
export const registerRepo = async (repoPath, meta, opts) => {
|
|
953
|
+
const { name, rename } = await withRegistryLock(() => registerRepoUnlocked(repoPath, meta, opts));
|
|
954
|
+
if (rename) {
|
|
955
|
+
try {
|
|
956
|
+
await opts?.onRename?.(rename.previousName, rename.nextName);
|
|
957
|
+
}
|
|
958
|
+
catch {
|
|
959
|
+
// The rename is already durable; observer failures cannot roll it back.
|
|
960
|
+
}
|
|
961
|
+
}
|
|
947
962
|
return name;
|
|
948
963
|
};
|
|
949
|
-
export const registerRepo = async (repoPath, meta, opts) => withRegistryLock(() => registerRepoUnlocked(repoPath, meta, opts));
|
|
950
964
|
/**
|
|
951
965
|
* Remove a repo from the global registry.
|
|
952
966
|
* Called after `gitnexus clean`.
|
package/package.json
CHANGED