diff --git a/packages/versioning/src/validate.ts b/packages/versioning/src/validate.ts index d3dd6f4e59..d74098dcd5 100644 --- a/packages/versioning/src/validate.ts +++ b/packages/versioning/src/validate.ts @@ -759,6 +759,7 @@ function validateAvailabilityForContains( for (const key of keySet) { const sourceVal = sourceAvail.get(key)!; const targetVal = targetAvail.get(key)!; + if (sourceVal === targetVal) continue; if ( [Availability.Added].includes(targetVal) && [Availability.Removed, Availability.Unavailable].includes(sourceVal) diff --git a/packages/versioning/src/versioning.ts b/packages/versioning/src/versioning.ts index 9eefb0d044..c48e11d4c2 100644 --- a/packages/versioning/src/versioning.ts +++ b/packages/versioning/src/versioning.ts @@ -773,10 +773,25 @@ export function getAvailabilityMap( ) return undefined; + let parentMap: Map | undefined = undefined; + if (type.kind === "ModelProperty" && type.model !== undefined) { + parentMap = getAvailabilityMap(program, type.model); + } else if (type.kind === "Operation" && type.interface !== undefined) { + parentMap = getAvailabilityMap(program, type.interface); + } + // implicitly, all versioned things are assumed to have been added at // v1 if not specified if (!added.length) { - added.push(allVersions[0]); + if (parentMap !== undefined) { + parentMap.forEach((key, value) => { + if (value === Availability.Added) { + added.push(allVersions.find((x) => x.name === key)!); + } + }); + } else { + added.push(allVersions[0]); + } } // something isn't available by default diff --git a/packages/versioning/test/versioning.test.ts b/packages/versioning/test/versioning.test.ts index f955bc4430..2b786f47d2 100644 --- a/packages/versioning/test/versioning.test.ts +++ b/packages/versioning/test/versioning.test.ts @@ -280,6 +280,34 @@ describe("versioning: logic", () => { ); }); + it("can be removed respecting model versioning", async () => { + const { + source, + projections: [v2, v3, v4], + } = await versionedModel( + ["v2", "v3", "v4"], + `@added(Versions.v2) + model Test { + a: int32; + @removed(Versions.v3) b: int32; + } + ` + ); + + assertHasProperties(v2, ["a", "b"]); + assertHasProperties(v3, ["a"]); + assertHasProperties(v4, ["a"]); + + assertModelProjectsTo( + [ + [v2, "v2"], + [v3, "v3"], + [v3, "v4"], + ], + source + ); + }); + it("can be renamed", async () => { const { source, @@ -1348,6 +1376,31 @@ describe("versioning: logic", () => { ); }); + it("can be removed respecting interface versioning", async () => { + const { + source, + projections: [v2, v3, v4], + } = await versionedInterface( + ["v2", "v3", "v4"], + `@added(Versions.v2) + interface Test { + allVersions(): void; + @removed(Versions.v3) version2Only(): void; + } + ` + ); + assertHasOperations(v2, ["allVersions", "version2Only"]); + assertHasOperations(v3, ["allVersions"]); + assertInterfaceProjectsTo( + [ + [v2, "v2"], + [v3, "v3"], + [v4, "v4"], + ], + source + ); + }); + it("can be renamed", async () => { const { source,