@typespec/versioning 0.57.0-dev.5 → 0.57.0-dev.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/decorators.d.ts +64 -0
- package/dist/src/decorators.d.ts.map +1 -0
- package/dist/src/decorators.js +304 -0
- package/dist/src/decorators.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/internal-projection-functions.d.ts +21 -0
- package/dist/src/internal-projection-functions.d.ts.map +1 -0
- package/dist/src/internal-projection-functions.js +88 -0
- package/dist/src/internal-projection-functions.js.map +1 -0
- package/dist/src/lib.d.ts +45 -45
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +15 -3
- package/dist/src/lib.js.map +1 -1
- package/dist/src/projection.d.ts +10 -0
- package/dist/src/projection.d.ts.map +1 -0
- package/dist/src/projection.js +38 -0
- package/dist/src/projection.js.map +1 -0
- package/dist/src/testing/index.d.ts +1 -1
- package/dist/src/testing/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/validate.d.ts +1 -1
- package/dist/src/validate.d.ts.map +1 -1
- package/dist/src/validate.js +3 -2
- package/dist/src/validate.js.map +1 -1
- package/dist/src/versioning-timeline.d.ts +2 -2
- package/dist/src/versioning-timeline.d.ts.map +1 -1
- package/dist/src/versioning-timeline.js.map +1 -1
- package/dist/src/versioning.d.ts +3 -89
- package/dist/src/versioning.d.ts.map +1 -1
- package/dist/src/versioning.js +88 -470
- package/dist/src/versioning.js.map +1 -1
- package/lib/decorators.tsp +180 -212
- package/lib/main.tsp +3 -0
- package/lib/{versioning.tsp → projection.tsp} +34 -2
- package/package.json +2 -2
package/dist/src/versioning.js
CHANGED
|
@@ -1,383 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { VersioningTimeline } from "./versioning-timeline.js";
|
|
4
|
-
const addedOnKey = createStateSymbol("addedOn");
|
|
5
|
-
const removedOnKey = createStateSymbol("removedOn");
|
|
6
|
-
const versionsKey = createStateSymbol("versions");
|
|
7
|
-
const versionDependencyKey = createStateSymbol("versionDependency");
|
|
8
|
-
const useDependencyNamespaceKey = createStateSymbol("useDependencyNamespace");
|
|
9
|
-
const useDependencyEnumKey = createStateSymbol("useDependencyEnum");
|
|
10
|
-
const renamedFromKey = createStateSymbol("renamedFrom");
|
|
11
|
-
const madeOptionalKey = createStateSymbol("madeOptional");
|
|
12
|
-
const madeRequiredKey = createStateSymbol("madeRequired");
|
|
13
|
-
const typeChangedFromKey = createStateSymbol("typeChangedFrom");
|
|
14
|
-
const returnTypeChangedFromKey = createStateSymbol("returnTypeChangedFrom");
|
|
15
|
-
export const namespace = "TypeSpec.Versioning";
|
|
16
|
-
function checkIsVersion(program, enumMember, diagnosticTarget) {
|
|
17
|
-
const version = getVersionForEnumMember(program, enumMember);
|
|
18
|
-
if (!version) {
|
|
19
|
-
reportDiagnostic(program, {
|
|
20
|
-
code: "version-not-found",
|
|
21
|
-
target: diagnosticTarget,
|
|
22
|
-
format: { version: enumMember.name, enumName: enumMember.enum.name },
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
return version;
|
|
26
|
-
}
|
|
27
|
-
export const $added = (context, t, v) => {
|
|
28
|
-
const { program } = context;
|
|
29
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
30
|
-
if (!version) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
// retrieve statemap to update or create a new one
|
|
34
|
-
const record = program.stateMap(addedOnKey).get(t) ?? new Array();
|
|
35
|
-
record.push(version);
|
|
36
|
-
// ensure that records are stored in ascending order
|
|
37
|
-
record.sort((a, b) => a.index - b.index);
|
|
38
|
-
program.stateMap(addedOnKey).set(t, record);
|
|
39
|
-
};
|
|
40
|
-
export function $removed(context, t, v) {
|
|
41
|
-
const { program } = context;
|
|
42
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
43
|
-
if (!version) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
// retrieve statemap to update or create a new one
|
|
47
|
-
const record = program.stateMap(removedOnKey).get(t) ?? new Array();
|
|
48
|
-
record.push(version);
|
|
49
|
-
// ensure that records are stored in ascending order
|
|
50
|
-
record.sort((a, b) => a.index - b.index);
|
|
51
|
-
program.stateMap(removedOnKey).set(t, record);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Returns the mapping of versions to old type values, if applicable
|
|
55
|
-
* @param p TypeSpec program
|
|
56
|
-
* @param t type to query
|
|
57
|
-
* @returns Map of versions to old types, if any
|
|
58
|
-
*/
|
|
59
|
-
export function getTypeChangedFrom(p, t) {
|
|
60
|
-
return p.stateMap(typeChangedFromKey).get(t);
|
|
61
|
-
}
|
|
62
|
-
export const $typeChangedFrom = (context, prop, v, oldType) => {
|
|
63
|
-
const { program } = context;
|
|
64
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
65
|
-
if (!version) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
// retrieve statemap to update or create a new one
|
|
69
|
-
let record = getTypeChangedFrom(program, prop) ?? new Map();
|
|
70
|
-
record.set(version, oldType);
|
|
71
|
-
// ensure the map is sorted by version
|
|
72
|
-
record = new Map([...record.entries()].sort((a, b) => a[0].index - b[0].index));
|
|
73
|
-
program.stateMap(typeChangedFromKey).set(prop, record);
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Returns the mapping of versions to old return type values, if applicable
|
|
77
|
-
* @param p TypeSpec program
|
|
78
|
-
* @param t type to query
|
|
79
|
-
* @returns Map of versions to old types, if any
|
|
80
|
-
*/
|
|
81
|
-
export function getReturnTypeChangedFrom(p, t) {
|
|
82
|
-
return p.stateMap(returnTypeChangedFromKey).get(t);
|
|
83
|
-
}
|
|
84
|
-
export const $returnTypeChangedFrom = (context, op, v, oldReturnType) => {
|
|
85
|
-
const { program } = context;
|
|
86
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
87
|
-
if (!version) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
// retrieve statemap to update or create a new one
|
|
91
|
-
let record = getReturnTypeChangedFrom(program, op) ?? new Map();
|
|
92
|
-
record.set(version, oldReturnType);
|
|
93
|
-
// ensure the map is sorted by version
|
|
94
|
-
record = new Map([...record.entries()].sort((a, b) => a[0].index - b[0].index));
|
|
95
|
-
program.stateMap(returnTypeChangedFromKey).set(op, record);
|
|
96
|
-
};
|
|
97
|
-
export const $renamedFrom = (context, t, v, oldName) => {
|
|
98
|
-
const { program } = context;
|
|
99
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
100
|
-
if (!version) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (oldName === "") {
|
|
104
|
-
reportDiagnostic(program, {
|
|
105
|
-
code: "invalid-renamed-from-value",
|
|
106
|
-
target: t,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
// retrieve statemap to update or create a new one
|
|
110
|
-
const record = getRenamedFrom(program, t) ?? [];
|
|
111
|
-
record.push({ version: version, oldName: oldName });
|
|
112
|
-
// ensure that records are stored in ascending order
|
|
113
|
-
record.sort((a, b) => a.version.index - b.version.index);
|
|
114
|
-
program.stateMap(renamedFromKey).set(t, record);
|
|
115
|
-
};
|
|
116
|
-
export const $madeOptional = (context, t, v) => {
|
|
117
|
-
const { program } = context;
|
|
118
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
119
|
-
if (!version) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
program.stateMap(madeOptionalKey).set(t, version);
|
|
123
|
-
};
|
|
124
|
-
export const $madeRequired = (context, t, v) => {
|
|
125
|
-
const { program } = context;
|
|
126
|
-
const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
|
|
127
|
-
if (!version) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
program.stateMap(madeRequiredKey).set(t, version);
|
|
131
|
-
};
|
|
132
|
-
/**
|
|
133
|
-
* @returns the array of RenamedFrom metadata if applicable.
|
|
134
|
-
*/
|
|
135
|
-
export function getRenamedFrom(p, t) {
|
|
136
|
-
return p.stateMap(renamedFromKey).get(t);
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* @returns the list of versions for which this decorator has been applied
|
|
140
|
-
*/
|
|
141
|
-
export function getRenamedFromVersions(p, t) {
|
|
142
|
-
return getRenamedFrom(p, t)?.map((x) => x.version);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* @returns get old name if applicable.
|
|
146
|
-
*/
|
|
147
|
-
export function getNameAtVersion(p, t, versionKey) {
|
|
148
|
-
const versioningState = getVersioningState(p, versionKey);
|
|
149
|
-
const allValues = getRenamedFrom(p, t);
|
|
150
|
-
if (!allValues)
|
|
151
|
-
return "";
|
|
152
|
-
for (const val of allValues) {
|
|
153
|
-
if (versioningState.timeline.isBefore(versioningState.projectingMoment, val.version)) {
|
|
154
|
-
return val.oldName;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return "";
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* @returns get old type if applicable.
|
|
161
|
-
*/
|
|
162
|
-
export function getTypeBeforeVersion(p, t, versionKey) {
|
|
163
|
-
const versioningState = getVersioningState(p, versionKey);
|
|
164
|
-
const map = getTypeChangedFrom(p, t);
|
|
165
|
-
if (!map)
|
|
166
|
-
return undefined;
|
|
167
|
-
for (const [changedAtVersion, oldType] of map) {
|
|
168
|
-
if (versioningState.timeline.isBefore(versioningState.projectingMoment, changedAtVersion)) {
|
|
169
|
-
return oldType;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return undefined;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* @returns get old type if applicable.
|
|
176
|
-
*/
|
|
177
|
-
export function getReturnTypeBeforeVersion(p, t, versionKey) {
|
|
178
|
-
const versioningState = getVersioningState(p, versionKey);
|
|
179
|
-
const map = getReturnTypeChangedFrom(p, t);
|
|
180
|
-
if (!map)
|
|
181
|
-
return "";
|
|
182
|
-
for (const [changedAtVersion, val] of map) {
|
|
183
|
-
if (versioningState.timeline.isBefore(versioningState.projectingMoment, changedAtVersion)) {
|
|
184
|
-
return val;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return "";
|
|
188
|
-
}
|
|
189
|
-
export function getAddedOnVersions(p, t) {
|
|
190
|
-
return p.stateMap(addedOnKey).get(t);
|
|
191
|
-
}
|
|
192
|
-
export function getRemovedOnVersions(p, t) {
|
|
193
|
-
return p.stateMap(removedOnKey).get(t);
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* @returns version when the given type was made optional if applicable.
|
|
197
|
-
*/
|
|
198
|
-
export function getMadeOptionalOn(p, t) {
|
|
199
|
-
return p.stateMap(madeOptionalKey).get(t);
|
|
200
|
-
}
|
|
201
|
-
/**
|
|
202
|
-
* @returns version when the given type was made required if applicable.
|
|
203
|
-
*/
|
|
204
|
-
export function getMadeRequiredOn(p, t) {
|
|
205
|
-
return p.stateMap(madeRequiredKey).get(t);
|
|
206
|
-
}
|
|
207
|
-
export class VersionMap {
|
|
208
|
-
map = new Map();
|
|
209
|
-
constructor(namespace, enumType) {
|
|
210
|
-
let index = 0;
|
|
211
|
-
for (const member of enumType.members.values()) {
|
|
212
|
-
this.map.set(member, {
|
|
213
|
-
name: member.name,
|
|
214
|
-
value: member.value?.toString() ?? member.name,
|
|
215
|
-
enumMember: member,
|
|
216
|
-
index,
|
|
217
|
-
namespace,
|
|
218
|
-
});
|
|
219
|
-
index++;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
getVersionForEnumMember(member) {
|
|
223
|
-
return this.map.get(member);
|
|
224
|
-
}
|
|
225
|
-
getVersions() {
|
|
226
|
-
return [...this.map.values()];
|
|
227
|
-
}
|
|
228
|
-
get size() {
|
|
229
|
-
return this.map.size;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
export const $versioned = (context, t, versions) => {
|
|
233
|
-
context.program.stateMap(versionsKey).set(t, new VersionMap(t, versions));
|
|
234
|
-
};
|
|
235
|
-
/**
|
|
236
|
-
* Get the version map of the namespace.
|
|
237
|
-
*/
|
|
238
|
-
export function getVersion(program, namespace) {
|
|
239
|
-
return program.stateMap(versionsKey).get(namespace);
|
|
240
|
-
}
|
|
241
|
-
export function findVersionedNamespace(program, namespace) {
|
|
242
|
-
let current = namespace;
|
|
243
|
-
while (current) {
|
|
244
|
-
if (program.stateMap(versionsKey).has(current)) {
|
|
245
|
-
return current;
|
|
246
|
-
}
|
|
247
|
-
current = current.namespace;
|
|
248
|
-
}
|
|
249
|
-
return undefined;
|
|
250
|
-
}
|
|
251
|
-
export function $useDependency(context, target, ...versionRecords) {
|
|
252
|
-
const versions = [];
|
|
253
|
-
// ensure only valid versions are passed in
|
|
254
|
-
for (const record of versionRecords) {
|
|
255
|
-
const ver = checkIsVersion(context.program, record, context.getArgumentTarget(0));
|
|
256
|
-
if (ver) {
|
|
257
|
-
versions.push(ver);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
if (target.kind === "Namespace") {
|
|
261
|
-
let state = context.program.stateMap(useDependencyNamespaceKey).get(target);
|
|
262
|
-
if (!state) {
|
|
263
|
-
state = versions;
|
|
264
|
-
}
|
|
265
|
-
else {
|
|
266
|
-
state.push(...versions);
|
|
267
|
-
}
|
|
268
|
-
context.program.stateMap(useDependencyNamespaceKey).set(target, state);
|
|
269
|
-
}
|
|
270
|
-
else if (target.kind === "EnumMember") {
|
|
271
|
-
const targetEnum = target.enum;
|
|
272
|
-
let state = context.program.stateMap(useDependencyEnumKey).get(targetEnum);
|
|
273
|
-
if (!state) {
|
|
274
|
-
state = new Map();
|
|
275
|
-
}
|
|
276
|
-
// get any existing versions and combine them
|
|
277
|
-
const currentVersions = state.get(target) ?? [];
|
|
278
|
-
currentVersions.push(...versions);
|
|
279
|
-
state.set(target, currentVersions);
|
|
280
|
-
context.program.stateMap(useDependencyEnumKey).set(targetEnum, state);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
export function getUseDependencies(program, target, searchEnum = true) {
|
|
284
|
-
const result = new Map();
|
|
285
|
-
if (target.kind === "Namespace") {
|
|
286
|
-
let current = target;
|
|
287
|
-
while (current) {
|
|
288
|
-
const data = program.stateMap(useDependencyNamespaceKey).get(current);
|
|
289
|
-
if (!data) {
|
|
290
|
-
// See if the namspace has a version enum
|
|
291
|
-
if (searchEnum) {
|
|
292
|
-
const versions = getVersion(program, current)?.getVersions();
|
|
293
|
-
if (versions?.length) {
|
|
294
|
-
const enumDeps = getUseDependencies(program, versions[0].enumMember.enum);
|
|
295
|
-
if (enumDeps) {
|
|
296
|
-
return enumDeps;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
current = current.namespace;
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
for (const v of data) {
|
|
304
|
-
result.set(v.namespace, v);
|
|
305
|
-
}
|
|
306
|
-
return result;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return undefined;
|
|
310
|
-
}
|
|
311
|
-
else if (target.kind === "Enum") {
|
|
312
|
-
const data = program.stateMap(useDependencyEnumKey).get(target);
|
|
313
|
-
if (!data) {
|
|
314
|
-
return undefined;
|
|
315
|
-
}
|
|
316
|
-
const resolved = resolveVersionDependency(program, data);
|
|
317
|
-
if (resolved instanceof Map) {
|
|
318
|
-
for (const [enumVer, value] of resolved) {
|
|
319
|
-
for (const val of value) {
|
|
320
|
-
const targetNamespace = val.enumMember.enum.namespace;
|
|
321
|
-
if (!targetNamespace) {
|
|
322
|
-
reportDiagnostic(program, {
|
|
323
|
-
code: "version-not-found",
|
|
324
|
-
target: val.enumMember.enum,
|
|
325
|
-
format: { version: val.enumMember.name, enumName: val.enumMember.enum.name },
|
|
326
|
-
});
|
|
327
|
-
return undefined;
|
|
328
|
-
}
|
|
329
|
-
let subMap = result.get(targetNamespace);
|
|
330
|
-
if (subMap) {
|
|
331
|
-
subMap.set(enumVer, val);
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
subMap = new Map([[enumVer, val]]);
|
|
335
|
-
}
|
|
336
|
-
result.set(targetNamespace, subMap);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return result;
|
|
342
|
-
}
|
|
343
|
-
function findVersionDependencyForNamespace(program, namespace) {
|
|
344
|
-
let current = namespace;
|
|
345
|
-
while (current) {
|
|
346
|
-
const data = program.stateMap(versionDependencyKey).get(current);
|
|
347
|
-
if (data) {
|
|
348
|
-
return data;
|
|
349
|
-
}
|
|
350
|
-
current = current.namespace;
|
|
351
|
-
}
|
|
352
|
-
return undefined;
|
|
353
|
-
}
|
|
1
|
+
import { getNamespaceFullName, } from "@typespec/compiler";
|
|
2
|
+
import { getAddedOnVersions, getRemovedOnVersions, getReturnTypeChangedFrom, getTypeChangedFrom, getUseDependencies, getVersion, } from "./decorators.js";
|
|
3
|
+
import { TimelineMoment, VersioningTimeline } from "./versioning-timeline.js";
|
|
354
4
|
export function getVersionDependencies(program, namespace) {
|
|
355
5
|
const useDeps = getUseDependencies(program, namespace);
|
|
356
6
|
if (useDeps) {
|
|
357
7
|
return useDeps;
|
|
358
8
|
}
|
|
359
|
-
|
|
360
|
-
if (data === undefined) {
|
|
361
|
-
return undefined;
|
|
362
|
-
}
|
|
363
|
-
const result = new Map();
|
|
364
|
-
for (const [key, value] of data) {
|
|
365
|
-
result.set(key, resolveVersionDependency(program, value));
|
|
366
|
-
}
|
|
367
|
-
return result;
|
|
368
|
-
}
|
|
369
|
-
function resolveVersionDependency(program, data) {
|
|
370
|
-
if (!(data instanceof Map)) {
|
|
371
|
-
return data;
|
|
372
|
-
}
|
|
373
|
-
const mapping = new Map();
|
|
374
|
-
for (const [key, value] of data) {
|
|
375
|
-
const sourceVersion = getVersionForEnumMember(program, key);
|
|
376
|
-
if (sourceVersion !== undefined) {
|
|
377
|
-
mapping.set(sourceVersion, value);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
return mapping;
|
|
9
|
+
return undefined;
|
|
381
10
|
}
|
|
382
11
|
/**
|
|
383
12
|
* Resolve the version of dependencies
|
|
@@ -441,42 +70,6 @@ export function resolveVersions(program, namespace) {
|
|
|
441
70
|
});
|
|
442
71
|
}
|
|
443
72
|
}
|
|
444
|
-
/**
|
|
445
|
-
* @internal
|
|
446
|
-
*/
|
|
447
|
-
export function indexTimeline(program, timeline, projectingMoment) {
|
|
448
|
-
const versionKey = program.checker.createType({
|
|
449
|
-
kind: "Object",
|
|
450
|
-
properties: {},
|
|
451
|
-
});
|
|
452
|
-
program.stateMap(versionIndexKey).set(versionKey, { timeline, projectingMoment });
|
|
453
|
-
return versionKey;
|
|
454
|
-
}
|
|
455
|
-
function getVersioningState(program, versionKey) {
|
|
456
|
-
return program.stateMap(versionIndexKey).get(versionKey);
|
|
457
|
-
}
|
|
458
|
-
const versionIndexKey = createStateSymbol("version-index");
|
|
459
|
-
export function buildVersionProjections(program, rootNs) {
|
|
460
|
-
const resolutions = resolveVersions(program, rootNs);
|
|
461
|
-
const timeline = new VersioningTimeline(program, resolutions.map((x) => x.versions));
|
|
462
|
-
return resolutions.map((resolution) => {
|
|
463
|
-
if (resolution.versions.size === 0) {
|
|
464
|
-
return { version: undefined, projections: [] };
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
467
|
-
const versionKey = indexTimeline(program, timeline, timeline.get(resolution.versions.values().next().value));
|
|
468
|
-
return {
|
|
469
|
-
version: resolution.rootVersion?.value,
|
|
470
|
-
projections: [
|
|
471
|
-
{
|
|
472
|
-
projectionName: "v",
|
|
473
|
-
arguments: [versionKey],
|
|
474
|
-
},
|
|
475
|
-
],
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
73
|
const versionCache = new WeakMap();
|
|
481
74
|
function cacheVersion(key, versions) {
|
|
482
75
|
versionCache.set(key, versions);
|
|
@@ -561,13 +154,58 @@ export var Availability;
|
|
|
561
154
|
Availability["Available"] = "Available";
|
|
562
155
|
Availability["Removed"] = "Removed";
|
|
563
156
|
})(Availability || (Availability = {}));
|
|
157
|
+
function getParentAddedVersion(program, type, versions) {
|
|
158
|
+
let parentMap = undefined;
|
|
159
|
+
if (type.kind === "ModelProperty" && type.model !== undefined) {
|
|
160
|
+
parentMap = getAvailabilityMap(program, type.model);
|
|
161
|
+
}
|
|
162
|
+
else if (type.kind === "Operation" && type.interface !== undefined) {
|
|
163
|
+
parentMap = getAvailabilityMap(program, type.interface);
|
|
164
|
+
}
|
|
165
|
+
if (parentMap === undefined)
|
|
166
|
+
return undefined;
|
|
167
|
+
for (const [key, value] of parentMap.entries()) {
|
|
168
|
+
if (value === Availability.Added) {
|
|
169
|
+
return versions.find((x) => x.name === key);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
function getParentAddedVersionInTimeline(program, type, timeline) {
|
|
175
|
+
let parentMap = undefined;
|
|
176
|
+
if (type.kind === "ModelProperty" && type.model !== undefined) {
|
|
177
|
+
parentMap = getAvailabilityMapInTimeline(program, type.model, timeline);
|
|
178
|
+
}
|
|
179
|
+
else if (type.kind === "Operation" && type.interface !== undefined) {
|
|
180
|
+
parentMap = getAvailabilityMapInTimeline(program, type.interface, timeline);
|
|
181
|
+
}
|
|
182
|
+
if (parentMap === undefined)
|
|
183
|
+
return undefined;
|
|
184
|
+
for (const [moment, availability] of parentMap.entries()) {
|
|
185
|
+
if (availability === Availability.Added) {
|
|
186
|
+
return moment.versions().next().value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Returns true if the first version modifier was @added, false if @removed.
|
|
193
|
+
*/
|
|
194
|
+
function resolveAddedFirst(added, removed) {
|
|
195
|
+
if (added.length === 0)
|
|
196
|
+
return false;
|
|
197
|
+
if (removed.length === 0)
|
|
198
|
+
return true;
|
|
199
|
+
return added[0].index < removed[0].index;
|
|
200
|
+
}
|
|
564
201
|
export function getAvailabilityMap(program, type) {
|
|
565
202
|
const avail = new Map();
|
|
566
203
|
const allVersions = getAllVersions(program, type);
|
|
567
204
|
// if unversioned then everything exists
|
|
568
205
|
if (allVersions === undefined)
|
|
569
206
|
return undefined;
|
|
570
|
-
const
|
|
207
|
+
const parentAdded = getParentAddedVersion(program, type, allVersions);
|
|
208
|
+
let added = getAddedOnVersions(program, type) ?? [];
|
|
571
209
|
const removed = getRemovedOnVersions(program, type) ?? [];
|
|
572
210
|
const typeChanged = getTypeChangedFrom(program, type);
|
|
573
211
|
const returnTypeChanged = getReturnTypeChangedFrom(program, type);
|
|
@@ -579,28 +217,25 @@ export function getAvailabilityMap(program, type) {
|
|
|
579
217
|
typeChanged === undefined &&
|
|
580
218
|
returnTypeChanged === undefined)
|
|
581
219
|
return undefined;
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
220
|
+
const wasAddedFirst = resolveAddedFirst(added, removed);
|
|
221
|
+
// implicitly, all versioned things are assumed to have been added at
|
|
222
|
+
// v1 if not specified, or inherited from their parent.
|
|
223
|
+
if (!wasAddedFirst && !parentAdded) {
|
|
224
|
+
// if the first version modifier was @removed, and the parent is implicitly available,
|
|
225
|
+
// then assume the type was available.
|
|
226
|
+
added = [allVersions[0], ...added];
|
|
585
227
|
}
|
|
586
|
-
else if (
|
|
587
|
-
|
|
228
|
+
else if (!added.length && !parentAdded) {
|
|
229
|
+
// no version information on the item or its parent implicitly means it has always been available
|
|
230
|
+
added.push(allVersions[0]);
|
|
588
231
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
compilerAssert(match !== undefined, "Version not found");
|
|
597
|
-
added.push(match);
|
|
598
|
-
}
|
|
599
|
-
});
|
|
600
|
-
}
|
|
601
|
-
else {
|
|
602
|
-
added.push(allVersions[0]);
|
|
603
|
-
}
|
|
232
|
+
else if (!added.length && parentAdded) {
|
|
233
|
+
// if no version info on type but is on parent, inherit that parent's "added" version
|
|
234
|
+
added.push(parentAdded);
|
|
235
|
+
}
|
|
236
|
+
else if (added.length && parentAdded) {
|
|
237
|
+
// if "added" info on both the type and parent, combine them
|
|
238
|
+
added = [parentAdded, ...added];
|
|
604
239
|
}
|
|
605
240
|
// something isn't available by default
|
|
606
241
|
let isAvail = false;
|
|
@@ -626,7 +261,8 @@ export function getAvailabilityMap(program, type) {
|
|
|
626
261
|
}
|
|
627
262
|
export function getAvailabilityMapInTimeline(program, type, timeline) {
|
|
628
263
|
const avail = new Map();
|
|
629
|
-
const
|
|
264
|
+
const parentAdded = getParentAddedVersionInTimeline(program, type, timeline);
|
|
265
|
+
let added = getAddedOnVersions(program, type) ?? [];
|
|
630
266
|
const removed = getRemovedOnVersions(program, type) ?? [];
|
|
631
267
|
const typeChanged = getTypeChangedFrom(program, type);
|
|
632
268
|
const returnTypeChanged = getReturnTypeChangedFrom(program, type);
|
|
@@ -638,10 +274,26 @@ export function getAvailabilityMapInTimeline(program, type, timeline) {
|
|
|
638
274
|
typeChanged === undefined &&
|
|
639
275
|
returnTypeChanged === undefined)
|
|
640
276
|
return undefined;
|
|
277
|
+
const wasAddedFirst = resolveAddedFirst(added, removed);
|
|
641
278
|
// implicitly, all versioned things are assumed to have been added at
|
|
642
|
-
// v1 if not specified
|
|
643
|
-
|
|
644
|
-
|
|
279
|
+
// v1 if not specified, or inherited from their parent.
|
|
280
|
+
const firstVersion = timeline.first().versions().next().value;
|
|
281
|
+
if (!wasAddedFirst && !parentAdded) {
|
|
282
|
+
// if the first version modifier was @removed, and the parent is implicitly available,
|
|
283
|
+
// then assume the type was available.
|
|
284
|
+
added = [firstVersion, ...added];
|
|
285
|
+
}
|
|
286
|
+
else if (!added.length && !parentAdded) {
|
|
287
|
+
// no version information on the item or its parent implicitly means it has always been available
|
|
288
|
+
added.push(firstVersion);
|
|
289
|
+
}
|
|
290
|
+
else if (!added.length && parentAdded) {
|
|
291
|
+
// if no version info on type but is on parent, inherit that parent's "added" version
|
|
292
|
+
added.push(parentAdded);
|
|
293
|
+
}
|
|
294
|
+
else if (added.length && parentAdded) {
|
|
295
|
+
// if "added" info on both the type and parent, combine them
|
|
296
|
+
added = [parentAdded, ...added];
|
|
645
297
|
}
|
|
646
298
|
// something isn't available by default
|
|
647
299
|
let isAvail = false;
|
|
@@ -665,40 +317,6 @@ export function getAvailabilityMapInTimeline(program, type, timeline) {
|
|
|
665
317
|
}
|
|
666
318
|
return avail;
|
|
667
319
|
}
|
|
668
|
-
export function existsAtVersion(p, type, versionKey) {
|
|
669
|
-
const versioningState = getVersioningState(p, versionKey);
|
|
670
|
-
// if unversioned then everything exists
|
|
671
|
-
const availability = getAvailabilityMapInTimeline(p, type, versioningState.timeline);
|
|
672
|
-
if (!availability)
|
|
673
|
-
return true;
|
|
674
|
-
const isAvail = availability.get(versioningState.projectingMoment);
|
|
675
|
-
return isAvail === Availability.Added || isAvail === Availability.Available;
|
|
676
|
-
}
|
|
677
|
-
export function hasDifferentNameAtVersion(p, type, version) {
|
|
678
|
-
return getNameAtVersion(p, type, version) !== "";
|
|
679
|
-
}
|
|
680
|
-
export function madeOptionalAfter(program, type, versionKey) {
|
|
681
|
-
const versioningState = getVersioningState(program, versionKey);
|
|
682
|
-
const madeOptionalAtVersion = getMadeOptionalOn(program, type);
|
|
683
|
-
if (madeOptionalAtVersion === undefined) {
|
|
684
|
-
return false;
|
|
685
|
-
}
|
|
686
|
-
return versioningState.timeline.isBefore(versioningState.projectingMoment, madeOptionalAtVersion);
|
|
687
|
-
}
|
|
688
|
-
export function madeRequiredAfter(program, type, versionKey) {
|
|
689
|
-
const versioningState = getVersioningState(program, versionKey);
|
|
690
|
-
const madeRequiredAtVersion = getMadeRequiredOn(program, type);
|
|
691
|
-
if (madeRequiredAtVersion === undefined) {
|
|
692
|
-
return false;
|
|
693
|
-
}
|
|
694
|
-
return versioningState.timeline.isBefore(versioningState.projectingMoment, madeRequiredAtVersion);
|
|
695
|
-
}
|
|
696
|
-
export function hasDifferentTypeAtVersion(p, type, version) {
|
|
697
|
-
return getTypeBeforeVersion(p, type, version) !== undefined;
|
|
698
|
-
}
|
|
699
|
-
export function hasDifferentReturnTypeAtVersion(p, type, version) {
|
|
700
|
-
return getReturnTypeBeforeVersion(p, type, version) !== "";
|
|
701
|
-
}
|
|
702
320
|
export function getVersionForEnumMember(program, member) {
|
|
703
321
|
// Always lookup for the original type. This ensure reference equality when comparing versions.
|
|
704
322
|
member = member.projectionBase ?? member;
|