forked from preconstruct/preconstruct
-
Notifications
You must be signed in to change notification settings - Fork 0
/
validate-package.ts
119 lines (109 loc) 路 4.19 KB
/
validate-package.ts
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
import { FatalError, FixableError } from "./errors";
import resolveFrom from "resolve-from";
import chalk from "chalk";
import { errors } from "./messages";
import { Package } from "./package";
let keys: <Obj>(obj: Obj) => (keyof Obj)[] = Object.keys;
export async function fixPackage(pkg: Package) {
if (pkg.entrypoints.length === 0) {
throw new FatalError(errors.noEntrypoints, pkg.name);
}
let fields = {
main: true,
module: pkg.entrypoints.some((x) => x.json.module !== undefined),
"umd:main": pkg.entrypoints.some((x) => x.json["umd:main"] !== undefined),
browser: pkg.entrypoints.some((x) => x.json.browser !== undefined),
worker: pkg.entrypoints.some((x) => x.json.worker !== undefined),
};
keys(fields)
.filter((x) => fields[x])
.forEach((field) => {
pkg.setFieldOnEntrypoints(field);
});
return (await Promise.all(pkg.entrypoints.map((x) => x.save()))).some(
(x) => x
);
}
let unsafeRequire = require;
export function validatePackage(pkg: Package) {
if (pkg.entrypoints.length === 0) {
throw new FatalError(errors.noEntrypoints, pkg.name);
}
let fields = {
// main is intentionally not here, since it's always required
// it will be validated in validateEntrypoint and the case
// which this function validates will never happen
module: pkg.entrypoints[0].json.module !== undefined,
"umd:main": pkg.entrypoints[0].json["umd:main"] !== undefined,
browser: pkg.entrypoints[0].json.browser !== undefined,
worker: pkg.entrypoints[0].json.worker !== undefined,
};
pkg.entrypoints.forEach((entrypoint) => {
keys(fields).forEach((field) => {
if (entrypoint.json[field] && !fields[field]) {
throw new FixableError(
`${entrypoint.name} has a ${field} build but ${pkg.entrypoints[0].name} does not have a ${field} build. Entrypoints in a package must either all have a particular build type or all not have a particular build type.`,
pkg.name
);
}
if (!entrypoint.json[field] && fields[field]) {
throw new FixableError(
`${pkg.entrypoints[0].name} has a ${field} build but ${entrypoint.name} does not have a ${field} build. Entrypoints in a package must either all have a particular build type or all not have a particular build type.`,
pkg.name
);
}
});
});
// TODO: do this well
if (fields["umd:main"]) {
// this is a sorta naive check
// but it's handling the most common case
// i don't think it's worth implementing this well at this exact moment
// because i'm guessing doing it well would cause more problems than it would solve
// this will likely change in the future
let sortaAllDeps = new Set([
...(pkg.json.peerDependencies
? Object.keys(pkg.json.peerDependencies)
: []),
...(pkg.json.dependencies ? Object.keys(pkg.json.dependencies) : []),
]);
for (let depName in pkg.json.dependencies) {
let depPkgJson: any;
try {
depPkgJson = unsafeRequire(
resolveFrom(pkg.directory, depName + "/package.json")
);
} catch (err) {
// ideally we'd resolve the packages ignoring the exports field but emitting
// the peer dependency error thing below isn't that important
// and having this be not broken for now is better
if (err.code === "ERR_PACKAGE_PATH_NOT_EXPORTED") {
continue;
}
throw err;
}
if (depPkgJson.peerDependencies) {
for (let pkgName in depPkgJson.peerDependencies) {
if (!sortaAllDeps.has(pkgName)) {
throw new FatalError(
`the package ${chalk.blue(pkg.name)} depends on ${chalk.blue(
depName
)} which has a peerDependency on ${chalk.blue(
pkgName
)} but ${chalk.blue(
pkgName
)} is not specified in the dependencies or peerDependencies of ${chalk.blue(
pkg.name
)}. please add ${chalk.blue(
pkgName
)} to the dependencies or peerDependencies of ${chalk.blue(
pkg.name
)}`,
pkg.name
);
}
}
}
}
}
}