-
Notifications
You must be signed in to change notification settings - Fork 318
Expand file tree
/
Copy pathassertions.ts
More file actions
127 lines (119 loc) · 3.73 KB
/
Copy pathassertions.ts
File metadata and controls
127 lines (119 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { Temporal } from "@js-temporal/polyfill";
import type { ParsedAuthoredData } from "./parse.ts";
import { isOrdinaryFeatureData } from "./type-guards.ts";
import type { WebFeaturesData } from "./types.quicktype.ts";
import type { BaselineHighLow, FeatureData, Status } from "./types.ts";
/**
* Assert that a reference from one feature to another is an ordinary feature
* reference (i.e., it's defined and not some kind of redirect).
*
* @export
* @param {string} sourceId The feature that is referencing another feature
* @param {string} targetId The feature being referenced
* @param {WebFeaturesData["features"]} features Feature data
*/
export function assertValidFeatureReference(
sourceId: string,
targetId: string,
features: WebFeaturesData["features"],
) {
const target: unknown = features[targetId];
if (target === undefined) {
throw new Error(`${sourceId} references a non-existent feature`);
}
if (!isOrdinaryFeatureData(target)) {
throw new Error(
`${sourceId} references a redirect "${targetId} instead of an ordinary feature ID`,
);
}
}
/**
* Assert that a discouraged feature with no supporting browsers has a
* `removal_date`.
*
* @export
* @param {string} id The ID of the feature to be checked
* @param {FeatureData} feature The ordinary feature data to be checked
*/
export function assertRequiredRemovalDateSet(
id: string,
feature: FeatureData,
): void {
if (!feature.discouraged) {
return;
}
if (feature.discouraged.removal_date) {
return;
}
if (Object.keys(feature.status.support).length > 0) {
return;
}
if (
feature.compat_features &&
Object.keys(feature.status.by_compat_key ?? {}).length > 0
)
return;
throw new Error(
`${id} is discouraged and has no reported support, so a removal date is required`,
);
}
/**
* Assert that `compat_features` keys are consistent with the feature's headline
* status.
*/
export function assertCompatSetConsistency(
id: string,
headline: Status,
featureData: ParsedAuthoredData,
) {
const { core, modifier } = featureData.compatFeatures;
for (const key of core) {
const perKeyStatus = headline.by_compat_key[key];
if (compareBaselineLevel(headline, perKeyStatus) > 0) {
throw new Error(
`${id}: core ${key} must be Baseline ${headline.baseline} or better (got ${perKeyStatus.baseline})`,
);
}
if (
headline.baseline_low_date &&
compareBaselineLowDates(headline, perKeyStatus) < 0
) {
throw new Error(
`${id}: core ${key} must be Baseline low on or after headline (got ${perKeyStatus.baseline_low_date}, expected ≥${headline.baseline_low_date})`,
);
}
}
for (const key of modifier) {
const perKeyStatus = headline.by_compat_key[key];
if (compareBaselineLevel(headline, perKeyStatus) > 0) {
throw new Error(
`${id}: modifier ${key} must be Baseline ${headline.baseline} or better (got ${perKeyStatus.baseline})`,
);
}
}
}
function compareBaselineLowDates(a: Status, b: Status): number {
const aLow = a.baseline_low_date;
const bLow = b.baseline_low_date;
if (aLow === undefined && bLow === undefined) {
return 0;
} else if (aLow !== undefined && bLow == undefined) {
return 1;
} else if (aLow === undefined && bLow !== undefined) {
return -1;
} else {
return Temporal.PlainDate.compare(
Temporal.PlainDate.from(aLow.replaceAll("≤", "")),
Temporal.PlainDate.from(bLow.replaceAll("≤", "")),
);
}
}
function compareBaselineLevel(a: Status, b: Status) {
const toNumber = new Map<BaselineHighLow | boolean, number>([
[false, 0],
["low", 1],
["high", 2],
]);
return toNumber.get(a.baseline) - toNumber.get(b.baseline);
}
// TODO: assertValidSnapshotReference