@typespec/versioning 0.41.0

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.
@@ -0,0 +1,782 @@
1
+ import { getNamespaceFullName, reportDeprecated, } from "@typespec/compiler";
2
+ import { createStateSymbol, reportDiagnostic } from "./lib.js";
3
+ const addedOnKey = createStateSymbol("addedOn");
4
+ const removedOnKey = createStateSymbol("removedOn");
5
+ const versionsKey = createStateSymbol("versions");
6
+ const versionDependencyKey = createStateSymbol("versionDependency");
7
+ const useDependencyNamespaceKey = createStateSymbol("useDependencyNamespace");
8
+ const useDependencyEnumKey = createStateSymbol("useDependencyEnum");
9
+ const renamedFromKey = createStateSymbol("renamedFrom");
10
+ const madeOptionalKey = createStateSymbol("madeOptional");
11
+ const typeChangedFromKey = createStateSymbol("typeChangedFrom");
12
+ const returnTypeChangedFromKey = createStateSymbol("returnTypeChangedFrom");
13
+ export const namespace = "TypeSpec.Versioning";
14
+ function checkIsVersion(program, enumMember, diagnosticTarget) {
15
+ const version = getVersionForEnumMember(program, enumMember);
16
+ if (!version) {
17
+ reportDiagnostic(program, {
18
+ code: "version-not-found",
19
+ target: diagnosticTarget,
20
+ format: { version: enumMember.name, enumName: enumMember.enum.name },
21
+ });
22
+ }
23
+ return version;
24
+ }
25
+ export function $added(context, t, v) {
26
+ var _a;
27
+ const { program } = context;
28
+ const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
29
+ if (!version) {
30
+ return;
31
+ }
32
+ // retrieve statemap to update or create a new one
33
+ const record = (_a = program.stateMap(addedOnKey).get(t)) !== null && _a !== void 0 ? _a : new Array();
34
+ record.push(version);
35
+ // ensure that records are stored in ascending order
36
+ record.sort((a, b) => a.index - b.index);
37
+ program.stateMap(addedOnKey).set(t, record);
38
+ }
39
+ export function $removed(context, t, v) {
40
+ var _a;
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 = (_a = program.stateMap(removedOnKey).get(t)) !== null && _a !== void 0 ? _a : 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 function $typeChangedFrom(context, prop, v, oldType) {
63
+ var _a;
64
+ const { program } = context;
65
+ const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
66
+ if (!version) {
67
+ return;
68
+ }
69
+ // retrieve statemap to update or create a new one
70
+ let record = (_a = getTypeChangedFrom(program, prop)) !== null && _a !== void 0 ? _a : new Map();
71
+ record.set(version, oldType);
72
+ // ensure the map is sorted by version
73
+ record = new Map([...record.entries()].sort((a, b) => a[0].index - b[0].index));
74
+ program.stateMap(typeChangedFromKey).set(prop, record);
75
+ }
76
+ /**
77
+ * Returns the mapping of versions to old return type values, if applicable
78
+ * @param p TypeSpec program
79
+ * @param t type to query
80
+ * @returns Map of versions to old types, if any
81
+ */
82
+ export function getReturnTypeChangedFrom(p, t) {
83
+ return p.stateMap(returnTypeChangedFromKey).get(t);
84
+ }
85
+ export function $returnTypeChangedFrom(context, op, v, oldReturnType) {
86
+ var _a;
87
+ const { program } = context;
88
+ const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
89
+ if (!version) {
90
+ return;
91
+ }
92
+ // retrieve statemap to update or create a new one
93
+ let record = (_a = getReturnTypeChangedFrom(program, op)) !== null && _a !== void 0 ? _a : new Map();
94
+ record.set(version, oldReturnType);
95
+ // ensure the map is sorted by version
96
+ record = new Map([...record.entries()].sort((a, b) => a[0].index - b[0].index));
97
+ program.stateMap(returnTypeChangedFromKey).set(op, record);
98
+ }
99
+ export function $renamedFrom(context, t, v, oldName) {
100
+ var _a;
101
+ const { program } = context;
102
+ const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
103
+ if (!version) {
104
+ return;
105
+ }
106
+ if (oldName === "") {
107
+ reportDiagnostic(program, {
108
+ code: "invalid-renamed-from-value",
109
+ target: t,
110
+ });
111
+ }
112
+ // retrieve statemap to update or create a new one
113
+ const record = (_a = getRenamedFrom(program, t)) !== null && _a !== void 0 ? _a : [];
114
+ record.push({ version: version, oldName: oldName });
115
+ // ensure that records are stored in ascending order
116
+ record.sort((a, b) => a.version.index - b.version.index);
117
+ program.stateMap(renamedFromKey).set(t, record);
118
+ }
119
+ export function $madeOptional(context, t, v) {
120
+ const { program } = context;
121
+ const version = checkIsVersion(context.program, v, context.getArgumentTarget(0));
122
+ if (!version) {
123
+ return;
124
+ }
125
+ program.stateMap(madeOptionalKey).set(t, version);
126
+ }
127
+ function toVersion(p, t, v) {
128
+ var _a;
129
+ const [namespace] = getVersions(p, t);
130
+ if (namespace === undefined) {
131
+ return undefined;
132
+ }
133
+ return getVersionForNamespace(p, v, (_a = namespace.projectionBase) !== null && _a !== void 0 ? _a : namespace);
134
+ }
135
+ function getRenamedFrom(p, t) {
136
+ return p.stateMap(renamedFromKey).get(t);
137
+ }
138
+ /**
139
+ * @deprecated since version 0.39.0. Use getRenamedFromVersions
140
+ * @returns version when the given type was added if applicable.
141
+ */
142
+ export function getRenamedFromVersion(p, t) {
143
+ var _a;
144
+ reportDeprecated(p, "Deprecated: getRenamedFromVersion is deprecated. Use getRenamedFromVersions instead.", t);
145
+ return (_a = p.stateMap(renamedFromKey).get(t)) === null || _a === void 0 ? void 0 : _a[0].version;
146
+ }
147
+ /**
148
+ * @returns the list of versions for which this decorator has been applied
149
+ */
150
+ export function getRenamedFromVersions(p, t) {
151
+ var _a;
152
+ return (_a = getRenamedFrom(p, t)) === null || _a === void 0 ? void 0 : _a.map((x) => x.version);
153
+ }
154
+ /**
155
+ * @deprecated since version 0.39.0. Use getNameAtVersion instead.
156
+ * @returns get old renamed name if applicable.
157
+ */
158
+ export function getRenamedFromOldName(p, t, v) {
159
+ var _a, _b;
160
+ reportDeprecated(p, "Deprecated: getRenamedFromOldName is deprecated. Use getNameAtVersion instead.", t);
161
+ return (_b = (_a = p.stateMap(renamedFromKey).get(t)) === null || _a === void 0 ? void 0 : _a[0].oldName) !== null && _b !== void 0 ? _b : "";
162
+ }
163
+ /**
164
+ * @returns get old name if applicable.
165
+ */
166
+ export function getNameAtVersion(p, t, v) {
167
+ const version = toVersion(p, t, v);
168
+ const allValues = getRenamedFrom(p, t);
169
+ if (!allValues || !version)
170
+ return "";
171
+ const targetIndex = version.index;
172
+ for (const val of allValues) {
173
+ const index = val.version.index;
174
+ if (targetIndex < index) {
175
+ return val.oldName;
176
+ }
177
+ }
178
+ return "";
179
+ }
180
+ /**
181
+ * @returns get old type if applicable.
182
+ */
183
+ export function getTypeBeforeVersion(p, t, v) {
184
+ const target = toVersion(p, t, v);
185
+ const map = getTypeChangedFrom(p, t);
186
+ if (!map || !target)
187
+ return undefined;
188
+ for (const [key, val] of map) {
189
+ if (target.index < key.index) {
190
+ return val;
191
+ }
192
+ }
193
+ return undefined;
194
+ }
195
+ /**
196
+ * @returns get old type if applicable.
197
+ */
198
+ export function getReturnTypeBeforeVersion(p, t, v) {
199
+ const target = toVersion(p, t, v);
200
+ const map = getReturnTypeChangedFrom(p, t);
201
+ if (!map || !target)
202
+ return "";
203
+ for (const [key, val] of map) {
204
+ if (target.index < key.index) {
205
+ return val;
206
+ }
207
+ }
208
+ return "";
209
+ }
210
+ /**
211
+ * @deprecated since version 0.39.0.
212
+ * @returns version when the given type was added if applicable.
213
+ */
214
+ export function getAddedOn(p, t) {
215
+ var _a;
216
+ reportDeprecated(p, "Deprecated: getAddedOn is deprecated. Use getAddedOnVersions.", t);
217
+ return (_a = p.stateMap(addedOnKey).get(t)) === null || _a === void 0 ? void 0 : _a[0];
218
+ }
219
+ /**
220
+ * @deprecated since version 0.39.0.
221
+ * @returns version when the given type was removed if applicable.
222
+ */
223
+ export function getRemovedOn(p, t) {
224
+ var _a;
225
+ reportDeprecated(p, "Deprecated: getRemovedOn is deprecated. Use getRemovedOnVersions.", t);
226
+ return (_a = p.stateMap(removedOnKey).get(t)) === null || _a === void 0 ? void 0 : _a[0];
227
+ }
228
+ export function getAddedOnVersions(p, t) {
229
+ return p.stateMap(addedOnKey).get(t);
230
+ }
231
+ export function getRemovedOnVersions(p, t) {
232
+ return p.stateMap(removedOnKey).get(t);
233
+ }
234
+ /**
235
+ * @returns version when the given type was made optional if applicable.
236
+ */
237
+ export function getMadeOptionalOn(p, t) {
238
+ return p.stateMap(madeOptionalKey).get(t);
239
+ }
240
+ export class VersionMap {
241
+ constructor(namespace, enumType) {
242
+ var _a, _b;
243
+ this.map = new Map();
244
+ let index = 0;
245
+ for (const member of enumType.members.values()) {
246
+ this.map.set(member, {
247
+ name: member.name,
248
+ value: (_b = (_a = member.value) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : member.name,
249
+ enumMember: member,
250
+ index,
251
+ namespace,
252
+ });
253
+ index++;
254
+ }
255
+ }
256
+ getVersionForEnumMember(member) {
257
+ return this.map.get(member);
258
+ }
259
+ getVersions() {
260
+ return [...this.map.values()];
261
+ }
262
+ get size() {
263
+ return this.map.size;
264
+ }
265
+ }
266
+ export function $versioned(context, t, versions) {
267
+ context.program.stateMap(versionsKey).set(t, new VersionMap(t, versions));
268
+ }
269
+ /**
270
+ * Get the version map of the namespace.
271
+ */
272
+ export function getVersion(program, namespace) {
273
+ return program.stateMap(versionsKey).get(namespace);
274
+ }
275
+ export function findVersionedNamespace(program, namespace) {
276
+ let current = namespace;
277
+ while (current) {
278
+ if (program.stateMap(versionsKey).has(current)) {
279
+ return current;
280
+ }
281
+ current = current.namespace;
282
+ }
283
+ return undefined;
284
+ }
285
+ export function $useDependency(context, target, ...versionRecords) {
286
+ var _a;
287
+ const versions = [];
288
+ // ensure only valid versions are passed in
289
+ for (const record of versionRecords) {
290
+ const ver = checkIsVersion(context.program, record, context.getArgumentTarget(0));
291
+ if (ver) {
292
+ versions.push(ver);
293
+ }
294
+ }
295
+ if (target.kind === "Namespace") {
296
+ let state = context.program.stateMap(useDependencyNamespaceKey).get(target);
297
+ if (!state) {
298
+ state = versions;
299
+ }
300
+ else {
301
+ state.push(...versions);
302
+ }
303
+ context.program.stateMap(useDependencyNamespaceKey).set(target, state);
304
+ }
305
+ else if (target.kind === "EnumMember") {
306
+ const targetEnum = target.enum;
307
+ let state = context.program.stateMap(useDependencyEnumKey).get(targetEnum);
308
+ if (!state) {
309
+ state = new Map();
310
+ }
311
+ // get any existing versions and combine them
312
+ const currentVersions = (_a = state.get(target)) !== null && _a !== void 0 ? _a : [];
313
+ currentVersions.push(...versions);
314
+ state.set(target, currentVersions);
315
+ context.program.stateMap(useDependencyEnumKey).set(targetEnum, state);
316
+ }
317
+ }
318
+ export function getUseDependencies(program, target, searchEnum = true) {
319
+ var _a;
320
+ const result = new Map();
321
+ if (target.kind === "Namespace") {
322
+ let current = target;
323
+ while (current) {
324
+ const data = program.stateMap(useDependencyNamespaceKey).get(current);
325
+ if (!data) {
326
+ // See if the namspace has a version enum
327
+ if (searchEnum) {
328
+ const versions = (_a = getVersion(program, current)) === null || _a === void 0 ? void 0 : _a.getVersions();
329
+ if (versions === null || versions === void 0 ? void 0 : versions.length) {
330
+ const enumDeps = getUseDependencies(program, versions[0].enumMember.enum);
331
+ if (enumDeps) {
332
+ return enumDeps;
333
+ }
334
+ }
335
+ }
336
+ current = current.namespace;
337
+ }
338
+ else {
339
+ for (const v of data) {
340
+ result.set(v.namespace, v);
341
+ }
342
+ return result;
343
+ }
344
+ }
345
+ return undefined;
346
+ }
347
+ else if (target.kind === "Enum") {
348
+ const data = program.stateMap(useDependencyEnumKey).get(target);
349
+ if (!data) {
350
+ return undefined;
351
+ }
352
+ const resolved = resolveVersionDependency(program, data);
353
+ if (resolved instanceof Map) {
354
+ for (const [enumVer, value] of resolved) {
355
+ for (const val of value) {
356
+ const targetNamespace = val.enumMember.enum.namespace;
357
+ if (!targetNamespace) {
358
+ reportDiagnostic(program, {
359
+ code: "version-not-found",
360
+ target: val.enumMember.enum,
361
+ format: { version: val.enumMember.name, enumName: val.enumMember.enum.name },
362
+ });
363
+ return undefined;
364
+ }
365
+ let subMap = result.get(targetNamespace);
366
+ if (subMap) {
367
+ subMap.set(enumVer, val);
368
+ }
369
+ else {
370
+ subMap = new Map([[enumVer, val]]);
371
+ }
372
+ result.set(targetNamespace, subMap);
373
+ }
374
+ }
375
+ }
376
+ }
377
+ return result;
378
+ }
379
+ export function $versionedDependency(context, referenceNamespace, versionRecord) {
380
+ const { program } = context;
381
+ reportDeprecated(program, "@versionedDependency is deprecated. Use @useDependency instead.", context.decoratorTarget);
382
+ let state = program.stateMap(versionDependencyKey).get(referenceNamespace);
383
+ if (!state) {
384
+ state = new Map();
385
+ context.program.stateMap(versionDependencyKey).set(referenceNamespace, state);
386
+ }
387
+ if (versionRecord.kind === "EnumMember") {
388
+ const v = checkIsVersion(program, versionRecord, context.getArgumentTarget(0));
389
+ if (v) {
390
+ state.set(v.namespace, v);
391
+ }
392
+ }
393
+ else {
394
+ let targetNamespace;
395
+ const versionMap = new Map();
396
+ for (const entry of versionRecord.values) {
397
+ if (entry.kind !== "Tuple") {
398
+ reportDiagnostic(context.program, { code: "versioned-dependency-tuple", target: entry });
399
+ continue;
400
+ }
401
+ const [sourceMember, targetMember] = entry.values;
402
+ if (sourceMember === undefined || sourceMember.kind !== "EnumMember") {
403
+ reportDiagnostic(context.program, {
404
+ code: "versioned-dependency-tuple-enum-member",
405
+ target: sourceMember !== null && sourceMember !== void 0 ? sourceMember : entry,
406
+ });
407
+ continue;
408
+ }
409
+ if (targetMember === undefined || targetMember.kind !== "EnumMember") {
410
+ reportDiagnostic(context.program, {
411
+ code: "versioned-dependency-tuple-enum-member",
412
+ target: targetMember !== null && targetMember !== void 0 ? targetMember : entry,
413
+ });
414
+ continue;
415
+ }
416
+ const targetVersion = checkIsVersion(program, targetMember, targetMember);
417
+ if (!targetVersion) {
418
+ continue;
419
+ }
420
+ if (targetNamespace === undefined) {
421
+ targetNamespace = targetVersion.namespace;
422
+ }
423
+ else if (targetNamespace !== targetVersion.namespace) {
424
+ reportDiagnostic(context.program, {
425
+ code: "versioned-dependency-same-namespace",
426
+ format: {
427
+ namespace1: getNamespaceFullName(targetNamespace),
428
+ namespace2: getNamespaceFullName(targetVersion.namespace),
429
+ },
430
+ target: targetMember,
431
+ });
432
+ return;
433
+ }
434
+ versionMap.set(sourceMember, targetVersion);
435
+ }
436
+ if (targetNamespace) {
437
+ state.set(targetNamespace, versionMap);
438
+ }
439
+ }
440
+ }
441
+ function findVersionDependencyForNamespace(program, namespace) {
442
+ let current = namespace;
443
+ while (current) {
444
+ const data = program.stateMap(versionDependencyKey).get(current);
445
+ if (data) {
446
+ return data;
447
+ }
448
+ current = current.namespace;
449
+ }
450
+ return undefined;
451
+ }
452
+ export function getVersionDependencies(program, namespace) {
453
+ const useDeps = getUseDependencies(program, namespace);
454
+ if (useDeps) {
455
+ return useDeps;
456
+ }
457
+ const data = findVersionDependencyForNamespace(program, namespace);
458
+ if (data === undefined) {
459
+ return undefined;
460
+ }
461
+ const result = new Map();
462
+ for (const [key, value] of data) {
463
+ result.set(key, resolveVersionDependency(program, value));
464
+ }
465
+ return result;
466
+ }
467
+ function resolveVersionDependency(program, data) {
468
+ if (!(data instanceof Map)) {
469
+ return data;
470
+ }
471
+ const mapping = new Map();
472
+ for (const [key, value] of data) {
473
+ const sourceVersion = getVersionForEnumMember(program, key);
474
+ if (sourceVersion !== undefined) {
475
+ mapping.set(sourceVersion, value);
476
+ }
477
+ }
478
+ return mapping;
479
+ }
480
+ /**
481
+ * Resolve the version to use for all namespace for each of the root namespace versions.
482
+ * @param program
483
+ * @param rootNs Root namespace.
484
+ */
485
+ export function resolveVersions(program, rootNs) {
486
+ var _a;
487
+ const versions = getVersion(program, rootNs);
488
+ const dependencies = (_a = getVersionDependencies(program, rootNs)) !== null && _a !== void 0 ? _a : new Map();
489
+ if (!versions) {
490
+ if (dependencies.size === 0) {
491
+ return [{ rootVersion: undefined, versions: new Map() }];
492
+ }
493
+ else {
494
+ const map = new Map();
495
+ for (const [dependencyNs, version] of dependencies) {
496
+ if (version instanceof Map) {
497
+ const rootNsName = getNamespaceFullName(rootNs);
498
+ const dependencyNsName = getNamespaceFullName(dependencyNs);
499
+ throw new Error(`Unexpected error: Namespace ${rootNsName} version dependency to ${dependencyNsName} should be a picked version.`);
500
+ }
501
+ map.set(dependencyNs, version);
502
+ }
503
+ return [{ rootVersion: undefined, versions: map }];
504
+ }
505
+ }
506
+ else {
507
+ return versions.getVersions().map((version) => {
508
+ const resolution = {
509
+ rootVersion: version,
510
+ versions: new Map(),
511
+ };
512
+ resolution.versions.set(rootNs, version);
513
+ for (const [dependencyNs, versionMap] of dependencies) {
514
+ if (!(versionMap instanceof Map)) {
515
+ const rootNsName = getNamespaceFullName(rootNs);
516
+ const dependencyNsName = getNamespaceFullName(dependencyNs);
517
+ throw new Error(`Unexpected error: Namespace ${rootNsName} version dependency to ${dependencyNsName} should be a mapping of version.`);
518
+ }
519
+ resolution.versions.set(dependencyNs, versionMap.get(version));
520
+ }
521
+ return resolution;
522
+ });
523
+ }
524
+ }
525
+ /**
526
+ * @internal
527
+ */
528
+ export function indexVersions(program, versions) {
529
+ const versionKey = program.checker.createType({
530
+ kind: "Object",
531
+ properties: {},
532
+ });
533
+ program.stateMap(key).set(versionKey, versions);
534
+ return versionKey;
535
+ }
536
+ function getVersionForNamespace(program, versionKey, namespaceType) {
537
+ var _a;
538
+ return (_a = program.stateMap(key).get(versionKey)) === null || _a === void 0 ? void 0 : _a.get(namespaceType);
539
+ }
540
+ const key = createStateSymbol("version-index");
541
+ export function buildVersionProjections(program, rootNs) {
542
+ const resolutions = resolveVersions(program, rootNs);
543
+ return resolutions.map((resolution) => {
544
+ var _a;
545
+ if (resolution.versions.size === 0) {
546
+ return { version: undefined, projections: [] };
547
+ }
548
+ else {
549
+ const versionKey = indexVersions(program, resolution.versions);
550
+ return {
551
+ version: (_a = resolution.rootVersion) === null || _a === void 0 ? void 0 : _a.value,
552
+ projections: [
553
+ {
554
+ projectionName: "v",
555
+ arguments: [versionKey],
556
+ },
557
+ ],
558
+ };
559
+ }
560
+ });
561
+ }
562
+ const versionCache = new WeakMap();
563
+ function cacheVersion(key, versions) {
564
+ versionCache.set(key, versions);
565
+ return versions;
566
+ }
567
+ export function getVersionsForEnum(program, en) {
568
+ const namespace = en.namespace;
569
+ if (namespace === undefined) {
570
+ return [];
571
+ }
572
+ const nsVersion = getVersion(program, namespace);
573
+ if (nsVersion === undefined) {
574
+ return [];
575
+ }
576
+ return [namespace, nsVersion];
577
+ }
578
+ export function getVersions(p, t) {
579
+ if (versionCache.has(t)) {
580
+ return versionCache.get(t);
581
+ }
582
+ if (t.kind === "Namespace") {
583
+ const nsVersion = getVersion(p, t);
584
+ if (nsVersion !== undefined) {
585
+ return cacheVersion(t, [t, nsVersion]);
586
+ }
587
+ else if (t.namespace) {
588
+ return cacheVersion(t, getVersions(p, t.namespace));
589
+ }
590
+ else {
591
+ return cacheVersion(t, [t, undefined]);
592
+ }
593
+ }
594
+ else if (t.kind === "Operation" ||
595
+ t.kind === "Interface" ||
596
+ t.kind === "Model" ||
597
+ t.kind === "Union" ||
598
+ t.kind === "Enum") {
599
+ if (t.namespace) {
600
+ return cacheVersion(t, getVersions(p, t.namespace) || []);
601
+ }
602
+ else if (t.kind === "Operation" && t.interface) {
603
+ return cacheVersion(t, getVersions(p, t.interface) || []);
604
+ }
605
+ else {
606
+ return cacheVersion(t, []);
607
+ }
608
+ }
609
+ else if (t.kind === "ModelProperty") {
610
+ if (t.sourceProperty) {
611
+ return getVersions(p, t.sourceProperty);
612
+ }
613
+ else if (t.model) {
614
+ return getVersions(p, t.model);
615
+ }
616
+ else {
617
+ return cacheVersion(t, []);
618
+ }
619
+ }
620
+ else if (t.kind === "EnumMember") {
621
+ return cacheVersion(t, getVersions(p, t.enum) || []);
622
+ }
623
+ else if (t.kind === "UnionVariant") {
624
+ return cacheVersion(t, getVersions(p, t.union) || []);
625
+ }
626
+ else {
627
+ return cacheVersion(t, []);
628
+ }
629
+ }
630
+ // these decorators take a `versionSource` parameter because not all types can walk up to
631
+ // the containing namespace. Model properties, for example.
632
+ /**
633
+ * @deprecated since version 0.39.0. Use existsAtVersion instead.
634
+ * @param p
635
+ * @param type
636
+ * @param version
637
+ * @returns
638
+ */
639
+ export function addedAfter(p, type, version) {
640
+ reportDeprecated(p, "Deprecated: addedAfter is deprecated. Use existsAtVersion instead.", type);
641
+ const appliesAt = appliesAtVersion(getAddedOn, p, type, version);
642
+ return appliesAt === null ? false : !appliesAt;
643
+ }
644
+ /**
645
+ * @deprecated since version 0.39.0. Use existsAtVersion instead.
646
+ * @param p
647
+ * @param type
648
+ * @param version
649
+ * @returns
650
+ */
651
+ export function removedOnOrBefore(p, type, version) {
652
+ reportDeprecated(p, "Deprecated: removedOnOrBefore is deprecated. Use existsAtVersion instead.", type);
653
+ const appliesAt = appliesAtVersion(getRemovedOn, p, type, version);
654
+ return appliesAt === null ? false : appliesAt;
655
+ }
656
+ function getAllVersions(p, t) {
657
+ var _a;
658
+ const [namespace, _] = getVersions(p, t);
659
+ if (namespace === undefined)
660
+ return undefined;
661
+ return (_a = getVersion(p, namespace)) === null || _a === void 0 ? void 0 : _a.getVersions();
662
+ }
663
+ export var Availability;
664
+ (function (Availability) {
665
+ Availability["Unavailable"] = "Unavailable";
666
+ Availability["Added"] = "Added";
667
+ Availability["Available"] = "Available";
668
+ Availability["Removed"] = "Removed";
669
+ })(Availability = Availability || (Availability = {}));
670
+ /**
671
+ * Returns a map of version names and whether a given type is available in that version
672
+ * @param program TypeSpec program
673
+ * @param type Type to get the availability map for
674
+ * @returns the availability map for the type, if applicable
675
+ */
676
+ export function getAvailabilityMap(program, type) {
677
+ var _a, _b;
678
+ const avail = new Map();
679
+ const allVersions = getAllVersions(program, type);
680
+ // if unversioned then everything exists
681
+ if (allVersions === undefined)
682
+ return undefined;
683
+ const added = (_a = getAddedOnVersions(program, type)) !== null && _a !== void 0 ? _a : [];
684
+ const removed = (_b = getRemovedOnVersions(program, type)) !== null && _b !== void 0 ? _b : [];
685
+ // if there's absolutely no versioning information, return undefined
686
+ // contextually, this might mean it inherits its versioning info from a parent
687
+ // or that it is treated as unversioned
688
+ if (!added.length && !removed.length)
689
+ return undefined;
690
+ // implicitly, all versioned things are assumed to have been added at
691
+ // v1 if not specified
692
+ if (!added.length) {
693
+ added.push(allVersions[0]);
694
+ }
695
+ // something isn't available by default
696
+ let isAvail = false;
697
+ for (const ver of allVersions) {
698
+ const add = added.find((x) => x.index === ver.index);
699
+ const rem = removed.find((x) => x.index === ver.index);
700
+ if (rem) {
701
+ isAvail = false;
702
+ avail.set(ver.name, Availability.Removed);
703
+ }
704
+ else if (add) {
705
+ isAvail = true;
706
+ avail.set(ver.name, Availability.Added);
707
+ }
708
+ else if (isAvail) {
709
+ avail.set(ver.name, Availability.Available);
710
+ }
711
+ else {
712
+ avail.set(ver.name, Availability.Unavailable);
713
+ }
714
+ }
715
+ return avail;
716
+ }
717
+ export function existsAtVersion(p, type, versionKey) {
718
+ const version = toVersion(p, type, versionKey);
719
+ // if unversioned then everything exists
720
+ if (version === undefined)
721
+ return true;
722
+ const availability = getAvailabilityMap(p, type);
723
+ if (!availability)
724
+ return true;
725
+ const isAvail = availability.get(version.name);
726
+ return [Availability.Added, Availability.Available].includes(isAvail);
727
+ }
728
+ /**
729
+ * @deprecated since version 0.39.0. Use hasDifferentNameAtVersion instead.
730
+ * @param p
731
+ * @param type
732
+ * @param version
733
+ * @returns
734
+ */
735
+ export function renamedAfter(p, type, version) {
736
+ reportDeprecated(p, "Deprecated: renamedAfter is deprecated. Use hasDifferentNameAtVersion instead.", type);
737
+ const appliesAt = appliesAtVersion(getRenamedFromVersion, p, type, version);
738
+ return appliesAt === null ? false : !appliesAt;
739
+ }
740
+ export function hasDifferentNameAtVersion(p, type, version) {
741
+ return getNameAtVersion(p, type, version) !== "";
742
+ }
743
+ export function madeOptionalAfter(p, type, version) {
744
+ const appliesAt = appliesAtVersion(getMadeOptionalOn, p, type, version);
745
+ return appliesAt === null ? false : !appliesAt;
746
+ }
747
+ export function hasDifferentTypeAtVersion(p, type, version) {
748
+ return getTypeBeforeVersion(p, type, version) !== undefined;
749
+ }
750
+ export function hasDifferentReturnTypeAtVersion(p, type, version) {
751
+ return getReturnTypeBeforeVersion(p, type, version) !== "";
752
+ }
753
+ export function getVersionForEnumMember(program, member) {
754
+ const parentEnum = member.enum;
755
+ if (!parentEnum) {
756
+ return undefined;
757
+ }
758
+ const [, versions] = getVersionsForEnum(program, parentEnum);
759
+ return versions === null || versions === void 0 ? void 0 : versions.getVersionForEnumMember(member);
760
+ }
761
+ /**
762
+ * returns either null, which means unversioned, or true or false depending
763
+ * on whether the change is active or not at that particular version
764
+ */
765
+ function appliesAtVersion(getMetadataFn, p, type, versionKey) {
766
+ const version = toVersion(p, type, versionKey);
767
+ if (version === undefined) {
768
+ return null;
769
+ }
770
+ const appliedOnVersion = getMetadataFn(p, type);
771
+ if (appliedOnVersion === undefined) {
772
+ return null;
773
+ }
774
+ const appliedOnVersionIndex = appliedOnVersion.index;
775
+ if (appliedOnVersionIndex === -1)
776
+ return null;
777
+ const testVersionIndex = version.index;
778
+ if (testVersionIndex === -1)
779
+ return null;
780
+ return testVersionIndex >= appliedOnVersionIndex;
781
+ }
782
+ //# sourceMappingURL=versioning.js.map