Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,16 @@ function fromSdkClient(
fromSdkClient(sdkContext, client.parent, rootApiVersions),
);
}
// fill children
// fill children, deduplicating to avoid duplicate entries in the code model
if (client.children) {
inputClient.children = client.children.map((c) =>
diagnostics.pipe(fromSdkClient(sdkContext, c, rootApiVersions)),
);
const seen = new Set<InputClient>();
inputClient.children = client.children
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can we just create a loop and skip processing any client that was already visited? Can we also add TODO to remove this once Azure/typespec-azure#4251 is fixed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 07b25f5. Replaced the .map().filter() chain with a loop that uses a Set<SdkClientType> to skip already-visited clients before converting them. Also added a TODO referencing Azure/typespec-azure#4251.

.map((c) => diagnostics.pipe(fromSdkClient(sdkContext, c, rootApiVersions)))
.filter((c) => {
if (seen.has(c)) return false;
seen.add(c);
return true;
});
}

return diagnostics.wrap(inputClient);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -458,3 +458,77 @@ describe("client name suffix", () => {
}
});
});

describe("client children deduplication", () => {
let runner: TestHost;

beforeEach(async () => {
runner = await createEmitterTestHost();
});

it("should not have duplicate children in the code model", async () => {
const program = await typeSpecCompile(
`
@service(#{
title: "Test Service",
})
@server(
"{endpoint}/client/structure/{client}",
"",
{
endpoint: url,
client: string,
}
)
namespace TestService {
@route("/one")
@post
op one(): void;

@route("/two")
@post
op two(): void;

interface Foo {
@route("/three")
@post
three(): void;
}
}

@client({
name: "FirstClient",
service: TestService,
})
namespace TestClientNs {
op one is TestService.one;

@client
interface Group3 {
Comment thread
jorgerangel-msft marked this conversation as resolved.
two is TestService.two;
three is TestService.Foo.three;
}
}
`,
runner,
{ IsNamespaceNeeded: false, IsTCGCNeeded: true },
);
const context = createEmitterContext(program);
const sdkContext = await createCSharpSdkContext(context);
const [root] = createModel(sdkContext);

const client = root.clients[0];
ok(client, "Client should exist");

if (client.children && client.children.length > 0) {
// Verify no duplicates by checking unique crossLanguageDefinitionIds
const childIds = client.children.map((c) => c.crossLanguageDefinitionId);
const uniqueIds = new Set(childIds);
strictEqual(
childIds.length,
uniqueIds.size,
`Client children should have no duplicates. Found: [${childIds.join(", ")}]`,
);
}
});
});
Loading