From fbd7930ab2424bf03d8d1edf68816467046fd9da Mon Sep 17 00:00:00 2001 From: Lee Stutzman Date: Sun, 5 Apr 2026 01:01:21 +0100 Subject: [PATCH] BUGFIX: Fix recursive alias detection causing infinite recursion (#2610) --- src/Alias.ts | 4 ++-- test/jest/Alias/Alias.test.ts | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/Alias.ts b/src/Alias.ts index f18daa6a8..67b2d7118 100644 --- a/src/Alias.ts +++ b/src/Alias.ts @@ -93,7 +93,7 @@ function applyAliases(origCommand: string, depth = 0, currentlyProcessingAliases // First get non-global aliases, and recursively apply them // (unless there are any reference loops or the reference chain is too deep) const localAlias = Aliases.get(commandArray[0]); - if (localAlias && !currentlyProcessingAliases.includes(localAlias)) { + if (localAlias && !currentlyProcessingAliases.includes(commandArray[0])) { const appliedAlias = applyAliases(localAlias, depth + 1, [commandArray[0], ...currentlyProcessingAliases]); commandArray.splice(0, 1, ...appliedAlias.split(" ")); } @@ -101,7 +101,7 @@ function applyAliases(origCommand: string, depth = 0, currentlyProcessingAliases // Once local aliasing is complete (or if none are present) handle any global aliases const processedCommands = commandArray.reduce((resolvedCommandArray: string[], command) => { const globalAlias = GlobalAliases.get(command); - if (globalAlias && !currentlyProcessingAliases.includes(globalAlias)) { + if (globalAlias && !currentlyProcessingAliases.includes(command)) { const appliedAlias = applyAliases(globalAlias, depth + 1, [command, ...currentlyProcessingAliases]); resolvedCommandArray.push(appliedAlias); } else { diff --git a/test/jest/Alias/Alias.test.ts b/test/jest/Alias/Alias.test.ts index d5f594fb7..589e907dc 100644 --- a/test/jest/Alias/Alias.test.ts +++ b/test/jest/Alias/Alias.test.ts @@ -1,5 +1,22 @@ -import { substituteAliases, parseAliasDeclaration } from "../../../src/Alias"; +import { Aliases, GlobalAliases, substituteAliases, parseAliasDeclaration } from "../../../src/Alias"; describe("substituteAliases Tests", () => { + beforeEach(() => { + Aliases.clear(); + GlobalAliases.clear(); + }); + + it("Should not infinitely recurse when alias value contains the alias name", () => { + parseAliasDeclaration("buy=buy -l"); + const result = substituteAliases("buy"); + expect(result).toEqual("buy -l"); + }); + + it("Should not infinitely recurse when global alias value contains the alias name", () => { + parseAliasDeclaration("scan=scan -d 5", true); + const result = substituteAliases("scan"); + expect(result).toEqual("scan -d 5"); + }); + it("Should gracefully handle recursive local aliases", () => { parseAliasDeclaration("recursiveAlias=b"); parseAliasDeclaration("b=c"); @@ -7,7 +24,7 @@ describe("substituteAliases Tests", () => { parseAliasDeclaration("d=recursiveAlias"); const result = substituteAliases("recursiveAlias"); - expect(result).toEqual("d"); + expect(result).toEqual("recursiveAlias"); }); it("Should only change local aliases if they are the start of the command", () => { @@ -27,7 +44,7 @@ describe("substituteAliases Tests", () => { parseAliasDeclaration("d=a", true); const result = substituteAliases("a b c d"); - expect(result).toEqual("d a b c"); + expect(result).toEqual("a b c d"); }); it("Should gracefully handle recursive mixed local and global aliases", () => { @@ -37,7 +54,7 @@ describe("substituteAliases Tests", () => { parseAliasDeclaration("d=recursiveAlias", false); const result = substituteAliases("recursiveAlias"); - expect(result).toEqual("d"); + expect(result).toEqual("recursiveAlias"); }); it("Should replace chained aliases", () => {