-
Notifications
You must be signed in to change notification settings - Fork 306
Expand file tree
/
Copy pathremove-tagged-compat-features.ts
More file actions
129 lines (114 loc) · 3.81 KB
/
Copy pathremove-tagged-compat-features.ts
File metadata and controls
129 lines (114 loc) · 3.81 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
128
129
import { setLogger } from "compute-baseline";
import { Compat, Feature } from "compute-baseline/browser-compat-data";
import { fdir } from "fdir";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { isDeepStrictEqual } from "node:util";
import winston from "winston";
import YAML from "yaml";
import yargs from "yargs";
import { checkForStaleCompat } from "./dist.js";
const compat = new Compat();
const argv = yargs(process.argv.slice(2))
.scriptName("remove-tagged-compat-features")
.usage(
"$0 [paths..]",
"Remove `compat_features` from `.yml` files that have an equivalently tagged set of features in @mdn/browser-compat-data",
)
.positional("paths", {
describe: "Directories or files to check/update.",
default: ["features"],
})
.option("force", {
alias: "f",
type: "boolean",
})
.option("verbose", {
alias: "v",
type: "count",
default: 0,
})
.parseSync();
const logger = winston.createLogger({
level: argv.verbose > 0 ? "debug" : "warn",
format: winston.format.combine(
winston.format.colorize(),
winston.format.simple(),
),
transports: new winston.transports.Console(),
});
let exitStatus = 0;
setLogger(logger);
const tagsToFeatures: Map<string, Feature[]> = (() => {
// TODO: Use Map.groupBy() instead, when it's available
const map = new Map();
for (const feature of compat.walk()) {
for (const tag of feature.tags) {
let features = map.get(tag);
if (!features) {
features = [];
map.set(tag, features);
}
features.push(feature);
}
}
return map;
})();
function cleanup(sourcePath: string, options?: { force?: boolean }): void {
options = { ...options };
const source = YAML.parseDocument(
fs.readFileSync(sourcePath, { encoding: "utf-8" }),
);
const { name: id } = path.parse(sourcePath);
// Collect tagged compat features. A `compat_features` list in the source
// takes precedence, but can be removed if it matches the tagged features.
const taggedCompatFeatures = (tagsToFeatures.get(`web-features:${id}`) ?? [])
.map((f) => `${f.id}`)
.sort();
const compat_features = (source.contents as any).items.find(
(p) => p.key.value === "compat_features",
);
if (compat_features) {
const { key: keyData, value: data } = compat_features;
const features = data.items.map((item) => item.value).sort();
if (options.force || isDeepStrictEqual(features, taggedCompatFeatures)) {
// Preserve comments around the compat_features key
const comments = keyData.commentBefore ? [keyData.commentBefore] : [];
data.items.reduce((acc, item) => {
if (item.commentBefore) acc.push(item.commentBefore);
if (item.comment) acc.push(item.comment);
return acc;
}, comments);
if (data.commentBefore) comments.push(data.commentBefore);
if (data.comment) comments.push(data.comment);
if (comments.length) {
source.comment = (source.comment || "") + comments.join("\n");
}
// Delete the key
(source.contents as any).delete("compat_features");
fs.writeFileSync(sourcePath, source.toString({ lineWidth: 0 }));
logger.info(`${id}: removed compat_features in favor of tag`);
}
}
}
function main() {
const filePaths: string[] = argv.paths.flatMap((fileOrDirectory) => {
if (fs.statSync(fileOrDirectory).isDirectory()) {
return new fdir()
.withBasePath()
.filter((path) => path.endsWith(".yml"))
.crawl(fileOrDirectory)
.sync();
}
return fileOrDirectory.endsWith(".yml") ? fileOrDirectory : [];
});
for (const sourcePath of filePaths) {
cleanup(sourcePath, { force: argv.force });
}
}
if (process.argv[1] === fileURLToPath(import.meta.url)) {
checkForStaleCompat();
main();
process.exit(exitStatus);
}