Skip to content

Commit f4555df

Browse files
clydinalan-agius4
authored andcommitted
refactor(@angular/cli): modularize list_projects tool logic
The main handler for the `list_projects` tool was becoming complex, with the main loop handling file parsing, version discovery, and multiple error paths. This change extracts the logic for processing a single `angular.json` file into a new `processConfigFile` helper function. This refactoring improves the codes structure by separating the orchestration logic in the main handler from the implementation details of processing a file. This leads to a more modular, readable, and maintainable codebase with no change to the tools external behavior or output.
1 parent 50e330d commit f4555df

File tree

1 file changed

+62
-17
lines changed

1 file changed

+62
-17
lines changed

packages/angular/cli/src/commands/mcp/tools/projects.ts

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,56 @@ async function loadAndParseWorkspace(
272272
}
273273
}
274274

275+
// Types for the structured output of the helper function.
276+
type VersioningError = z.infer<typeof listProjectsOutputSchema.versioningErrors>[number];
277+
278+
/**
279+
* Processes a single `angular.json` file to extract workspace and framework version information.
280+
* @param configFile The path to the `angular.json` file.
281+
* @param searchRoot The directory at which to stop the upward search for `package.json`.
282+
* @param seenPaths A Set of absolute paths that have already been processed to avoid duplicates.
283+
* @param versionCache A Map to cache framework version lookups for performance.
284+
* @returns A promise resolving to an object containing the processed data and any errors.
285+
*/
286+
async function processConfigFile(
287+
configFile: string,
288+
searchRoot: string,
289+
seenPaths: Set<string>,
290+
versionCache: Map<string, string | undefined>,
291+
): Promise<{
292+
workspace?: WorkspaceData;
293+
parsingError?: ParsingError;
294+
versioningError?: VersioningError;
295+
}> {
296+
const { workspace, error } = await loadAndParseWorkspace(configFile, seenPaths);
297+
if (error) {
298+
return { parsingError: error };
299+
}
300+
301+
if (!workspace) {
302+
return {}; // Skipped as it was already seen.
303+
}
304+
305+
try {
306+
const workspaceDir = path.dirname(configFile);
307+
workspace.frameworkVersion = await findAngularCoreVersion(
308+
workspaceDir,
309+
versionCache,
310+
searchRoot,
311+
);
312+
313+
return { workspace };
314+
} catch (e) {
315+
return {
316+
workspace,
317+
versioningError: {
318+
filePath: workspace.path,
319+
message: e instanceof Error ? e.message : 'An unknown error occurred.',
320+
},
321+
};
322+
}
323+
}
324+
275325
async function createListProjectsHandler({ server }: McpToolContext) {
276326
return async () => {
277327
const workspaces: WorkspaceData[] = [];
@@ -292,27 +342,22 @@ async function createListProjectsHandler({ server }: McpToolContext) {
292342

293343
for (const root of searchRoots) {
294344
for await (const configFile of findAngularJsonFiles(root)) {
295-
const { workspace, error } = await loadAndParseWorkspace(configFile, seenPaths);
296-
if (error) {
297-
parsingErrors.push(error);
298-
}
345+
const { workspace, parsingError, versioningError } = await processConfigFile(
346+
configFile,
347+
root,
348+
seenPaths,
349+
versionCache,
350+
);
299351

300352
if (workspace) {
301-
try {
302-
const workspaceDir = path.dirname(configFile);
303-
workspace.frameworkVersion = await findAngularCoreVersion(
304-
workspaceDir,
305-
versionCache,
306-
root,
307-
);
308-
} catch (e) {
309-
versioningErrors.push({
310-
filePath: workspace.path,
311-
message: e instanceof Error ? e.message : 'An unknown error occurred.',
312-
});
313-
}
314353
workspaces.push(workspace);
315354
}
355+
if (parsingError) {
356+
parsingErrors.push(parsingError);
357+
}
358+
if (versioningError) {
359+
versioningErrors.push(versioningError);
360+
}
316361
}
317362
}
318363

0 commit comments

Comments
 (0)