-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmakeIndex.mjs
95 lines (80 loc) · 3.02 KB
/
makeIndex.mjs
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
/**
* This script expands the "exportPatterns" key in a package.json to the
* "exports" key. Node supports wildcards in the "exports" field but TypeScript
* support for auto-import sucks a bit.
*
* Normally the resolution algorithm works in reverse to what we're trying to do
* here: it starts with an import from say "package/components/Widget" and then
* looks in the "exports" field for a matching key. Here we're trying to infer
* all the possible keys from the file system, but since a key can map to
* multiple files, this could get tricky. Therefore we expect an extra "src"
* key, which points to the files that should be used to generate the keys.
*
* @see {@link https://github.com/microsoft/TypeScript/issues/53116}
*/
import { readFile, readdir, writeFile } from "fs/promises";
import { join, posix, resolve } from "path";
import Prettier from "prettier";
const packageJson = JSON.parse(await readFile("package.json", "utf8"));
const prettierConfig = await Prettier.resolveConfig("package.json");
if (!packageJson.exportPatterns) {
console.error(`no "exportPatterns" section found in package.json`);
process.exit(1);
}
packageJson.exports = await expandPatterns(packageJson.exportPatterns);
await writePretty("package.json", JSON.stringify(packageJson, null, 2));
async function writePretty(path, data) {
await writeFile(
path,
await Prettier.format(data, {
filepath: path,
...prettierConfig,
}),
);
}
async function expandPatterns(patterns, cwd = resolve(".")) {
const expanded = {};
for (const [key, value] of Object.entries(patterns)) {
if (typeof value === "string" || !value.src) {
if (key.includes("*")) {
console.warn(`WARN: key "${key}": no value for "src" given`);
}
expanded[key] = value;
continue;
}
const { src, ...rest } = value;
const srcArray = Array.isArray(src) ? src : [src];
for (const src of srcArray) {
const fileName = posix.basename(src);
const dir = posix.dirname(src);
const starIndex = fileName.indexOf("*");
if (starIndex === -1) {
console.error(
`export "${key}": the "src" value must contain a wildcard`,
);
process.exit(1);
}
const prefix = fileName.slice(0, starIndex);
const suffix = fileName.slice(starIndex + 1);
const files = await readdir(join(cwd, dir));
for (const file of files) {
if (!file.startsWith(prefix) || !file.endsWith(suffix)) {
continue;
}
const replacement = file.slice(prefix.length, -suffix.length);
let conditions = Object.fromEntries(
Object.entries(rest).map(([k, v]) => [
k,
v.replace("*", replacement),
]),
);
if (Object.keys(conditions).length === 1 && "default" in conditions) {
// collapse an object like { default: '...' } into '...' directly.
conditions = conditions.default;
}
expanded[key.replace("*", replacement)] = conditions;
}
}
}
return expanded;
}