gitnexus 1.6.6-rc.53 → 1.6.6-rc.55
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/group/sync.js
CHANGED
|
@@ -64,22 +64,22 @@ export async function syncGroup(config, opts) {
|
|
|
64
64
|
let manifestCrossLinks = [];
|
|
65
65
|
let dbExecutors;
|
|
66
66
|
let registryEntries;
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
67
|
+
const openPoolIds = [];
|
|
68
|
+
try {
|
|
69
|
+
const eo = opts?.extractorOverride;
|
|
70
|
+
if (eo && eo.length === 0) {
|
|
71
|
+
autoContracts = await eo();
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
registryEntries = await readRegistry();
|
|
75
|
+
const entries = registryEntries;
|
|
76
|
+
const resolve = opts?.resolveRepoHandle ?? defaultResolveHandle(entries);
|
|
77
|
+
const httpEx = new HttpRouteExtractor();
|
|
78
|
+
const grpcEx = new GrpcExtractor();
|
|
79
|
+
const thriftEx = new ThriftExtractor();
|
|
80
|
+
const topicEx = new TopicExtractor();
|
|
81
|
+
const includeEx = new IncludeExtractor();
|
|
82
|
+
dbExecutors = new Map();
|
|
83
83
|
for (const [groupPath, regName] of Object.entries(config.repos)) {
|
|
84
84
|
const handle = await resolve(regName, groupPath);
|
|
85
85
|
if (!handle) {
|
|
@@ -166,55 +166,49 @@ export async function syncGroup(config, opts) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
// Workspace discovery and manifest extraction run inside this outer try
|
|
170
|
+
// block so dbExecutors closures resolve against live pools (issue #1802).
|
|
171
|
+
// The finally below closes pools after this completes (or throws).
|
|
172
|
+
let allLinks = [...config.links];
|
|
173
|
+
if (config.detect.workspace_deps) {
|
|
174
|
+
const repoPaths = new Map();
|
|
175
|
+
if (!registryEntries)
|
|
176
|
+
registryEntries = await readRegistry();
|
|
177
|
+
for (const [groupPath, regName] of Object.entries(config.repos)) {
|
|
178
|
+
const e = registryEntries.find((en) => en.name === regName);
|
|
179
|
+
if (e)
|
|
180
|
+
repoPaths.set(groupPath, e.path);
|
|
172
181
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const repoPaths = new Map();
|
|
181
|
-
if (!registryEntries)
|
|
182
|
-
registryEntries = await readRegistry();
|
|
183
|
-
for (const [groupPath, regName] of Object.entries(config.repos)) {
|
|
184
|
-
const e = registryEntries.find((en) => en.name === regName);
|
|
185
|
-
if (e)
|
|
186
|
-
repoPaths.set(groupPath, e.path);
|
|
187
|
-
}
|
|
188
|
-
const wsResult = await discoverWorkspaceLinks(config.repos, repoPaths, dbExecutors);
|
|
189
|
-
if (wsResult.links.length > 0) {
|
|
190
|
-
allLinks = [...allLinks, ...wsResult.links];
|
|
191
|
-
if (opts?.verbose) {
|
|
192
|
-
for (const s of wsResult.stats) {
|
|
193
|
-
logger.info(` workspace-deps: discovered ${s.linkCount} cross-${s.ecosystem.toLowerCase()} links from ${s.projectCount} ${s.ecosystem} projects`);
|
|
182
|
+
const wsResult = await discoverWorkspaceLinks(config.repos, repoPaths, dbExecutors);
|
|
183
|
+
if (wsResult.links.length > 0) {
|
|
184
|
+
allLinks = [...allLinks, ...wsResult.links];
|
|
185
|
+
if (opts?.verbose) {
|
|
186
|
+
for (const s of wsResult.stats) {
|
|
187
|
+
logger.info(` workspace-deps: discovered ${s.linkCount} cross-${s.ecosystem.toLowerCase()} links from ${s.projectCount} ${s.ecosystem} projects`);
|
|
188
|
+
}
|
|
194
189
|
}
|
|
195
190
|
}
|
|
196
191
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
192
|
+
if (allLinks.length > 0) {
|
|
193
|
+
const knownRepos = new Set(Object.keys(config.repos));
|
|
194
|
+
for (const link of allLinks) {
|
|
195
|
+
const dangling = [link.from, link.to].filter((r) => !knownRepos.has(r));
|
|
196
|
+
if (dangling.length > 0) {
|
|
197
|
+
logger.warn(`[group/sync] manifest link ${link.type}:${link.contract} references repos not in config.repos: ${dangling.join(', ')} — cross-links will use synthetic UIDs`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const manifestEx = new ManifestExtractor();
|
|
201
|
+
const manifestResult = await manifestEx.extractFromManifest(allLinks, dbExecutors);
|
|
202
|
+
autoContracts.push(...manifestResult.contracts);
|
|
203
|
+
manifestCrossLinks = manifestResult.crossLinks;
|
|
204
|
+
if (opts?.verbose) {
|
|
205
|
+
logger.info(` manifest: ${manifestCrossLinks.length} cross-links from ${allLinks.length} links (${config.links.length} declared + ${allLinks.length - config.links.length} discovered)`);
|
|
210
206
|
}
|
|
211
207
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (opts?.verbose) {
|
|
217
|
-
logger.info(` manifest: ${manifestCrossLinks.length} cross-links from ${allLinks.length} links (${config.links.length} declared + ${allLinks.length - config.links.length} discovered)`);
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
for (const id of [...new Set(openPoolIds)]) {
|
|
211
|
+
await closeLbug(id).catch(() => { });
|
|
218
212
|
}
|
|
219
213
|
}
|
|
220
214
|
const providerIndex = buildProviderIndex(autoContracts, config.matching);
|
|
@@ -293,6 +293,9 @@ export function populatePhpNamespaceSiblings(parsedFiles, indexes, inputs) {
|
|
|
293
293
|
//
|
|
294
294
|
// Additionally, mirror from files that are imported via `use` (different
|
|
295
295
|
// namespace) so return types from dependencies are chain-followable too.
|
|
296
|
+
const parsedByPath = new Map();
|
|
297
|
+
for (const p of parsedFiles)
|
|
298
|
+
parsedByPath.set(p.filePath, p);
|
|
296
299
|
for (const parsed of parsedFiles) {
|
|
297
300
|
const moduleScope = parsed.scopes.find((s) => s.kind === 'Module');
|
|
298
301
|
if (moduleScope === undefined)
|
|
@@ -328,7 +331,7 @@ export function populatePhpNamespaceSiblings(parsedFiles, indexes, inputs) {
|
|
|
328
331
|
}
|
|
329
332
|
// Mirror return-type bindings from accessible files.
|
|
330
333
|
for (const srcFilePath of accessibleFiles) {
|
|
331
|
-
const srcParsed =
|
|
334
|
+
const srcParsed = parsedByPath.get(srcFilePath);
|
|
332
335
|
if (srcParsed === undefined)
|
|
333
336
|
continue;
|
|
334
337
|
const srcModuleScope = srcParsed.scopes.find((s) => s.kind === 'Module');
|
|
@@ -78,9 +78,11 @@ export type ScopeExtractorHooks = Pick<LanguageProvider, 'resolveScopeKind' | 'b
|
|
|
78
78
|
* Drive the five extraction passes and return a `ParsedFile`.
|
|
79
79
|
*
|
|
80
80
|
* Throws `ScopeTreeInvariantError` (from #912) when the provider emits
|
|
81
|
-
* captures that violate structural scope invariants.
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
81
|
+
* captures that violate structural scope invariants (e.g., overlapping
|
|
82
|
+
* sibling scopes). When no `@scope.module` capture is present, a
|
|
83
|
+
* synthetic Module scope is created spanning all captures, and orphan
|
|
84
|
+
* non-Module scopes are re-parented under it. This enables indexing of
|
|
85
|
+
* files where tree-sitter produces an ERROR root (e.g., complex .phtml
|
|
86
|
+
* templates with mixed PHP/HTML/JS).
|
|
85
87
|
*/
|
|
86
88
|
export declare function extract(matches: readonly CaptureMatch[], filePath: string, provider: ScopeExtractorHooks): ParsedFile;
|
|
@@ -65,17 +65,28 @@ import { extractTemplateArguments } from './utils/template-arguments.js';
|
|
|
65
65
|
* Drive the five extraction passes and return a `ParsedFile`.
|
|
66
66
|
*
|
|
67
67
|
* Throws `ScopeTreeInvariantError` (from #912) when the provider emits
|
|
68
|
-
* captures that violate structural scope invariants.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
68
|
+
* captures that violate structural scope invariants (e.g., overlapping
|
|
69
|
+
* sibling scopes). When no `@scope.module` capture is present, a
|
|
70
|
+
* synthetic Module scope is created spanning all captures, and orphan
|
|
71
|
+
* non-Module scopes are re-parented under it. This enables indexing of
|
|
72
|
+
* files where tree-sitter produces an ERROR root (e.g., complex .phtml
|
|
73
|
+
* templates with mixed PHP/HTML/JS).
|
|
72
74
|
*/
|
|
73
75
|
export function extract(matches, filePath, provider) {
|
|
74
76
|
// Partition matches by topic up front — one linear pass over the input.
|
|
75
77
|
const partitioned = partitionByTopic(matches);
|
|
76
78
|
// ── Pass 1: build the scope tree ─────────────────────────────────────
|
|
77
79
|
const scopeDrafts = pass1BuildScopes(partitioned.scope, filePath, provider);
|
|
78
|
-
const moduleScope = ensureModuleScope(scopeDrafts,
|
|
80
|
+
const moduleScope = ensureModuleScope(scopeDrafts, filePath, matches);
|
|
81
|
+
// Re-parent orphan drafts (parent === null, non-Module) under the
|
|
82
|
+
// Module scope. Replaces drafts with new ones carrying the correct
|
|
83
|
+
// parent — runs before content passes so bindings/ownedDefs are empty.
|
|
84
|
+
for (let i = 0; i < scopeDrafts.length; i++) {
|
|
85
|
+
const d = scopeDrafts[i];
|
|
86
|
+
if (d.parent === null && d.kind !== 'Module') {
|
|
87
|
+
scopeDrafts[i] = makeDraft(d.id, moduleScope.id, d.kind, d.range, d.filePath);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
79
90
|
const scopes = scopeDrafts.map(draftToScope);
|
|
80
91
|
// buildScopeTree validates invariants (throws on violation) and exposes
|
|
81
92
|
// the lookup contract consumed by Passes 2-5.
|
|
@@ -171,18 +182,29 @@ function topicOf(match) {
|
|
|
171
182
|
}
|
|
172
183
|
return 'unknown';
|
|
173
184
|
}
|
|
174
|
-
function ensureModuleScope(scopeDrafts,
|
|
185
|
+
function ensureModuleScope(scopeDrafts, filePath, allMatches) {
|
|
175
186
|
const moduleScope = scopeDrafts.find((s) => s.kind === 'Module');
|
|
176
187
|
if (moduleScope !== undefined)
|
|
177
188
|
return moduleScope;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
// Synthesize a Module scope spanning all captures in the file.
|
|
190
|
+
// Computed from ALL captures (scope, declaration, reference, etc.)
|
|
191
|
+
// so the range covers top-level references that appear after the
|
|
192
|
+
// last inner scope — not just inner Function/Class scopes.
|
|
193
|
+
let endLine = 0;
|
|
194
|
+
let endCol = 0;
|
|
195
|
+
for (const match of allMatches) {
|
|
196
|
+
for (const capture of Object.values(match)) {
|
|
197
|
+
if (capture.range.endLine > endLine ||
|
|
198
|
+
(capture.range.endLine === endLine && capture.range.endCol > endCol)) {
|
|
199
|
+
endLine = capture.range.endLine;
|
|
200
|
+
endCol = capture.range.endCol;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
183
203
|
}
|
|
184
|
-
|
|
185
|
-
|
|
204
|
+
const range = { startLine: 0, startCol: 0, endLine, endCol };
|
|
205
|
+
const synthetic = makeDraft(makeScopeId({ filePath, range, kind: 'Module' }), null, 'Module', range, filePath);
|
|
206
|
+
scopeDrafts.push(synthetic);
|
|
207
|
+
return synthetic;
|
|
186
208
|
}
|
|
187
209
|
function draftToScope(draft) {
|
|
188
210
|
const frozenBindings = new Map();
|
package/package.json
CHANGED