Skip to content

Commit 6b0be28

Browse files
authored
Specific scope decorator should always override all-scopes decorator (#2390)
Resolves #1961
1 parent 7f1dd16 commit 6b0be28

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: feature
3+
packages:
4+
- "@azure-tools/typespec-client-generator-core"
5+
---
6+
7+
Specific scope decorator should always override all-scopes decorator

packages/typespec-client-generator-core/src/decorators.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,20 @@ function setScopedDecoratorData(
107107
value: unknown,
108108
scope?: LanguageScopes,
109109
) {
110+
const targetEntry = context.program.stateMap(key).get(target);
110111
// if no scope specified, then set with the new value
111112
if (!scope) {
112-
context.program.stateMap(key).set(target, Object.fromEntries([[AllScopes, value]]));
113+
if (targetEntry && targetEntry[AllScopes]) {
114+
targetEntry[AllScopes] = value;
115+
} else {
116+
const newObject = Object.fromEntries([[AllScopes, value]]);
117+
context.program
118+
.stateMap(key)
119+
.set(target, !targetEntry ? newObject : { ...targetEntry, ...newObject });
120+
}
113121
return;
114122
}
115123

116-
const targetEntry = context.program.stateMap(key).get(target);
117124
const [negationScopes, scopes] = parseScopes(context, scope);
118125
if (negationScopes !== undefined && negationScopes.length > 0) {
119126
// override the previous value for negation scopes

packages/typespec-client-generator-core/test/decorators/scope.test.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ it("first scoped decorator then non-scoped decorator", async () => {
158158
emitterName: "@azure-tools/typespec-csharp",
159159
});
160160
const { func: funcCsharp } = (await runnerWithCsharp.compile(code)) as { func: Operation };
161-
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "internal");
161+
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "public");
162162
});
163163

164164
it("first non-scoped augmented decorator then scoped augmented decorator", async () => {
@@ -202,10 +202,10 @@ it("first scoped augmented decorator then non-scoped augmented decorator", async
202202
emitterName: "@azure-tools/typespec-csharp",
203203
});
204204
const { func: funcCsharp } = (await runnerWithCsharp.compile(code)) as { func: Operation };
205-
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "public");
205+
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "internal");
206206
});
207207

208-
it("two scoped decorator", async () => {
208+
it("two scoped decorators", async () => {
209209
const code = `
210210
@test
211211
@access(Access.internal, "csharp")
@@ -226,6 +226,27 @@ it("two scoped decorator", async () => {
226226
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "internal");
227227
});
228228

229+
it("two non-scoped decorators", async () => {
230+
const code = `
231+
@test
232+
@access(Access.internal)
233+
@access(Access.public)
234+
op func(
235+
@query("createdAt")
236+
createdAt: utcDateTime;
237+
): void;
238+
`;
239+
240+
const { func } = (await runner.compile(code)) as { func: Operation };
241+
strictEqual(getAccess(runner.context, func), "internal");
242+
243+
const runnerWithCsharp = await createSdkTestRunner({
244+
emitterName: "@azure-tools/typespec-csharp",
245+
});
246+
const { func: funcCsharp } = (await runnerWithCsharp.compile(code)) as { func: Operation };
247+
strictEqual(getAccess(runnerWithCsharp.context, funcCsharp), "internal");
248+
});
249+
229250
it("csv scope list", async () => {
230251
function getCodeTemplate(language: string) {
231252
return `

0 commit comments

Comments
 (0)