@monorepolint/rules 0.5.0-alpha.82 → 0.5.0-alpha.85
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.
- package/lib/__tests__/alphabeticalScripts.spec.js +22 -24
- package/lib/__tests__/alphabeticalScripts.spec.js.map +1 -1
- package/lib/__tests__/bannedDependencies.spec.js +67 -9
- package/lib/__tests__/bannedDependencies.spec.js.map +1 -1
- package/lib/__tests__/consistentDependencies.spec.js +11 -10
- package/lib/__tests__/consistentDependencies.spec.js.map +1 -1
- package/lib/__tests__/consistentVersions.spec.js +23 -22
- package/lib/__tests__/consistentVersions.spec.js.map +1 -1
- package/lib/__tests__/fileContents.spec.js +25 -32
- package/lib/__tests__/fileContents.spec.js.map +1 -1
- package/lib/__tests__/mustSatisfyPeerDependencies.spec.js +49 -48
- package/lib/__tests__/mustSatisfyPeerDependencies.spec.js.map +1 -1
- package/lib/__tests__/nestedWorkspaces.spec.js +10 -8
- package/lib/__tests__/nestedWorkspaces.spec.js.map +1 -1
- package/lib/__tests__/packageEntry.spec.js +47 -40
- package/lib/__tests__/packageEntry.spec.js.map +1 -1
- package/lib/__tests__/packageOrder.spec.js +34 -33
- package/lib/__tests__/packageOrder.spec.js.map +1 -1
- package/lib/__tests__/packageScript.spec.js +50 -51
- package/lib/__tests__/packageScript.spec.js.map +1 -1
- package/lib/__tests__/requireDependency.spec.js +12 -11
- package/lib/__tests__/requireDependency.spec.js.map +1 -1
- package/lib/__tests__/utils.d.ts +68 -1
- package/lib/__tests__/utils.d.ts.map +1 -1
- package/lib/__tests__/utils.js +70 -21
- package/lib/__tests__/utils.js.map +1 -1
- package/lib/alphabeticalDependencies.js +3 -3
- package/lib/alphabeticalDependencies.js.map +1 -1
- package/lib/alphabeticalScripts.js +1 -1
- package/lib/alphabeticalScripts.js.map +1 -1
- package/lib/bannedDependencies.d.ts +21 -12
- package/lib/bannedDependencies.d.ts.map +1 -1
- package/lib/bannedDependencies.js +86 -57
- package/lib/bannedDependencies.js.map +1 -1
- package/lib/consistentDependencies.d.ts +6 -6
- package/lib/consistentDependencies.d.ts.map +1 -1
- package/lib/consistentDependencies.js +2 -3
- package/lib/consistentDependencies.js.map +1 -1
- package/lib/consistentVersions.d.ts +1 -1
- package/lib/consistentVersions.js +8 -8
- package/lib/consistentVersions.js.map +1 -1
- package/lib/fileContents.d.ts +8 -8
- package/lib/fileContents.d.ts.map +1 -1
- package/lib/fileContents.js +32 -31
- package/lib/fileContents.js.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/mustSatisfyPeerDependencies.d.ts +31 -31
- package/lib/mustSatisfyPeerDependencies.d.ts.map +1 -1
- package/lib/mustSatisfyPeerDependencies.js +18 -16
- package/lib/mustSatisfyPeerDependencies.js.map +1 -1
- package/lib/packageEntry.d.ts +11 -20
- package/lib/packageEntry.d.ts.map +1 -1
- package/lib/packageEntry.js +15 -7
- package/lib/packageEntry.js.map +1 -1
- package/lib/packageOrder.d.ts +3 -3
- package/lib/packageOrder.d.ts.map +1 -1
- package/lib/packageOrder.js +2 -3
- package/lib/packageOrder.js.map +1 -1
- package/lib/packageScript.d.ts +10 -10
- package/lib/packageScript.js +4 -4
- package/lib/packageScript.js.map +1 -1
- package/lib/requireDependency.d.ts +6 -6
- package/lib/requireDependency.d.ts.map +1 -1
- package/lib/requireDependency.js +3 -3
- package/lib/requireDependency.js.map +1 -1
- package/lib/standardTsconfig.d.ts +10 -10
- package/lib/standardTsconfig.d.ts.map +1 -1
- package/lib/standardTsconfig.js +26 -21
- package/lib/standardTsconfig.js.map +1 -1
- package/lib/util/checkAlpha.d.ts +1 -0
- package/lib/util/checkAlpha.d.ts.map +1 -1
- package/lib/util/checkAlpha.js +8 -5
- package/lib/util/checkAlpha.js.map +1 -1
- package/lib/util/makeDirectory.js +2 -2
- package/lib/util/makeDirectory.js.map +1 -1
- package/lib/util/packageDependencyGraphService.d.ts +3 -3
- package/lib/util/packageDependencyGraphService.d.ts.map +1 -1
- package/lib/util/packageDependencyGraphService.js +3 -3
- package/lib/util/packageDependencyGraphService.js.map +1 -1
- package/package.json +8 -9
- package/src/__tests__/alphabeticalScripts.spec.ts +27 -28
- package/src/__tests__/bannedDependencies.spec.ts +80 -6
- package/src/__tests__/consistentDependencies.spec.ts +11 -6
- package/src/__tests__/consistentVersions.spec.ts +32 -27
- package/src/__tests__/fileContents.spec.ts +32 -40
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +52 -47
- package/src/__tests__/nestedWorkspaces.spec.ts +12 -6
- package/src/__tests__/packageEntry.spec.ts +64 -45
- package/src/__tests__/packageOrder.spec.ts +46 -40
- package/src/__tests__/packageScript.spec.ts +62 -54
- package/src/__tests__/requireDependency.spec.ts +11 -6
- package/src/__tests__/utils.ts +109 -19
- package/src/bannedDependencies.ts +106 -74
- package/src/consistentDependencies.ts +1 -2
- package/src/consistentVersions.ts +2 -2
- package/src/fileContents.ts +32 -30
- package/src/mustSatisfyPeerDependencies.ts +6 -2
- package/src/packageEntry.ts +13 -5
- package/src/packageOrder.ts +1 -2
- package/src/packageScript.ts +2 -2
- package/src/requireDependency.ts +2 -2
- package/src/standardTsconfig.ts +22 -19
- package/src/util/checkAlpha.ts +6 -3
- package/src/util/packageDependencyGraphService.ts +8 -5
- package/tsconfig.tsbuildinfo +1 -6233
|
@@ -6,109 +6,141 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import minimatch from "minimatch";
|
|
9
|
+
import { matchesAnyGlob } from "@monorepolint/utils";
|
|
10
|
+
import { AggregateTiming } from "@monorepolint/utils";
|
|
12
11
|
import path from "path";
|
|
13
12
|
import * as r from "runtypes";
|
|
14
13
|
import { IPackageDependencyGraphNode, PackageDependencyGraphService } from "./util/packageDependencyGraphService";
|
|
15
14
|
|
|
15
|
+
// FIXME: This rule is messed. bannedTransitiveDependencies doesnt glob
|
|
16
|
+
|
|
17
|
+
const bannedDepGlobsField = r.Union(
|
|
18
|
+
r.Array(r.String),
|
|
19
|
+
r.Record({
|
|
20
|
+
glob: r.Array(r.String).optional(),
|
|
21
|
+
exact: r.Array(r.String).optional(),
|
|
22
|
+
})
|
|
23
|
+
);
|
|
24
|
+
|
|
16
25
|
const Options = r.Union(
|
|
17
|
-
r
|
|
18
|
-
.Record({
|
|
19
|
-
bannedDependencies: r.Array(r.String),
|
|
20
|
-
})
|
|
21
|
-
.And(
|
|
22
|
-
r.Partial({
|
|
23
|
-
bannedTransitiveDependencies: r.Undefined,
|
|
24
|
-
})
|
|
25
|
-
),
|
|
26
|
-
r
|
|
27
|
-
.Record({
|
|
28
|
-
bannedTransitiveDependencies: r.Array(r.String),
|
|
29
|
-
})
|
|
30
|
-
.And(
|
|
31
|
-
r.Partial({
|
|
32
|
-
bannedDependencies: r.Undefined,
|
|
33
|
-
})
|
|
34
|
-
),
|
|
35
26
|
r.Record({
|
|
36
|
-
bannedDependencies:
|
|
27
|
+
bannedDependencies: bannedDepGlobsField,
|
|
28
|
+
bannedTransitiveDependencies: r.Undefined.optional(),
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
r.Record({
|
|
32
|
+
bannedDependencies: bannedDepGlobsField.optional(),
|
|
37
33
|
bannedTransitiveDependencies: r.Array(r.String),
|
|
34
|
+
}),
|
|
35
|
+
|
|
36
|
+
r.Record({
|
|
37
|
+
bannedDependencies: bannedDepGlobsField.optional(),
|
|
38
|
+
bannedTransitiveDependencies: r.Array(r.String).optional(),
|
|
38
39
|
})
|
|
39
40
|
);
|
|
40
41
|
|
|
41
42
|
export type Options = r.Static<typeof Options>;
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
/**
|
|
45
|
+
* We use this locally to avoid making a billion sets. Because check is called once per package
|
|
46
|
+
* (with the exact same config object reference) we can save quite a bit of time by reusing this cache.
|
|
47
|
+
*/
|
|
48
|
+
const setCache = new Map<ReadonlyArray<string>, Set<string>>();
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
checkBanned(context, bannedDependencies, "dependencies");
|
|
50
|
-
checkBanned(context, bannedDependencies, "devDependencies");
|
|
51
|
-
checkBanned(context, bannedDependencies, "peerDependencies");
|
|
52
|
-
}
|
|
50
|
+
const aggregateTiming = new AggregateTiming(":bannedDependencies stats");
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
};
|
|
52
|
+
export const bannedDependencies: RuleModule<typeof Options> & {
|
|
53
|
+
printStats: () => void;
|
|
54
|
+
} = {
|
|
55
|
+
check: function expectAllowedDependencies(context, opts, extra) {
|
|
56
|
+
aggregateTiming.start(extra?.id ?? "unknown id");
|
|
60
57
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// tslint:disable-next-line:no-shadowed-variable
|
|
64
|
-
bannedDependencies: ReadonlyArray<string>,
|
|
65
|
-
block: "dependencies" | "devDependencies" | "peerDependencies"
|
|
66
|
-
) {
|
|
67
|
-
const packageJson = context.getPackageJson();
|
|
68
|
-
const packagePath = context.getPackageJsonPath();
|
|
58
|
+
const packageJson = context.getPackageJson();
|
|
59
|
+
const packagePath = context.getPackageJsonPath();
|
|
69
60
|
|
|
70
|
-
|
|
61
|
+
const curDeps = packageJson.dependencies && Object.keys(packageJson.dependencies);
|
|
62
|
+
const curDevDeps = packageJson.devDependencies && Object.keys(packageJson.devDependencies);
|
|
63
|
+
const curPeerDeps = packageJson.peerDependencies && Object.keys(packageJson.peerDependencies);
|
|
71
64
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
const { bannedDependencies: banned, bannedTransitiveDependencies: transitives } = opts;
|
|
66
|
+
|
|
67
|
+
const globs = banned && (Array.isArray(banned) ? banned : banned.glob);
|
|
68
|
+
const exacts = banned && (Array.isArray(banned) ? undefined : banned.exact);
|
|
75
69
|
|
|
76
|
-
|
|
77
|
-
const violations: string[] = [];
|
|
70
|
+
const violations = new Set<string>();
|
|
78
71
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
if (globs) {
|
|
73
|
+
if (curDeps) populateProblemsGlobs(globs, curDeps, violations);
|
|
74
|
+
if (curDevDeps) populateProblemsGlobs(globs, curDevDeps, violations);
|
|
75
|
+
if (curPeerDeps) populateProblemsGlobs(globs, curPeerDeps, violations);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (exacts) {
|
|
79
|
+
let set = setCache.get(exacts);
|
|
80
|
+
if (set === undefined) {
|
|
81
|
+
set = new Set(exacts);
|
|
82
|
+
setCache.set(exacts, set);
|
|
84
83
|
}
|
|
84
|
+
if (curDeps) populateProblemsExact(set, curDeps, violations);
|
|
85
|
+
if (curDevDeps) populateProblemsExact(set, curDevDeps, violations);
|
|
86
|
+
if (curPeerDeps) populateProblemsExact(set, curPeerDeps, violations);
|
|
85
87
|
}
|
|
86
|
-
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
if (violations.size > 0) {
|
|
90
|
+
context.addError({
|
|
91
|
+
file: packagePath,
|
|
92
|
+
message:
|
|
93
|
+
`Found ${violations.size} banned dependencies of package.json:\n\t` +
|
|
94
|
+
Array.from(violations)
|
|
95
|
+
.map((v) => `'${v}'`)
|
|
96
|
+
.join(", "),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (transitives) {
|
|
101
|
+
let set = setCache.get(transitives);
|
|
102
|
+
if (set === undefined) {
|
|
103
|
+
set = new Set(transitives);
|
|
104
|
+
setCache.set(transitives, set);
|
|
105
|
+
}
|
|
106
|
+
checkTransitives(context, set);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
aggregateTiming.stop();
|
|
110
|
+
},
|
|
111
|
+
optionsRuntype: Options,
|
|
112
|
+
printStats: () => {
|
|
113
|
+
aggregateTiming.printResults();
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
function populateProblemsExact(banned: Set<string>, dependencies: ReadonlyArray<string>, violations: Set<string>) {
|
|
118
|
+
for (const dependency of dependencies) {
|
|
119
|
+
if (banned.has(dependency)) {
|
|
120
|
+
violations.add(dependency);
|
|
121
|
+
}
|
|
99
122
|
}
|
|
100
123
|
}
|
|
101
124
|
|
|
102
|
-
function
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
function populateProblemsGlobs(
|
|
126
|
+
bannedDependencyGlobs: ReadonlyArray<string>,
|
|
127
|
+
dependencies: ReadonlyArray<string>,
|
|
128
|
+
violations: Set<string>
|
|
106
129
|
) {
|
|
130
|
+
for (const dependency of dependencies) {
|
|
131
|
+
if (matchesAnyGlob(dependency, bannedDependencyGlobs)) {
|
|
132
|
+
violations.add(dependency);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// This function is slow. God help you if you use this on a big repo
|
|
138
|
+
function checkTransitives(context: Context, banned: Set<string>) {
|
|
107
139
|
const graphService = new PackageDependencyGraphService();
|
|
108
|
-
const root = graphService.buildDependencyGraph(path.resolve(context.getPackageJsonPath()));
|
|
140
|
+
const root = graphService.buildDependencyGraph(path.resolve(context.getPackageJsonPath()), context.host);
|
|
109
141
|
for (const { dependencies, importPath } of graphService.traverse(root)) {
|
|
110
142
|
for (const [dependency] of dependencies) {
|
|
111
|
-
if (
|
|
143
|
+
if (banned.has(dependency)) {
|
|
112
144
|
// Remove the starting package since it's obvious in CLI output.
|
|
113
145
|
const [, ...importPathWithoutRoot] = importPath;
|
|
114
146
|
const pathing = [...importPathWithoutRoot.map(nameOrPackageJsonPath), dependency].join(" -> ");
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import { writeJson } from "@monorepolint/utils";
|
|
10
9
|
import diff from "jest-diff";
|
|
11
10
|
import * as r from "runtypes";
|
|
12
11
|
|
|
@@ -59,7 +58,7 @@ function checkDeps(context: Context, args: Options, block: "dependencies" | "dev
|
|
|
59
58
|
fixer: () => {
|
|
60
59
|
const newPackageJson = { ...packageJson };
|
|
61
60
|
newPackageJson[block] = expectedDependencies;
|
|
62
|
-
writeJson(packagePath, newPackageJson);
|
|
61
|
+
context.host.writeJson(packagePath, newPackageJson);
|
|
63
62
|
},
|
|
64
63
|
});
|
|
65
64
|
}
|
|
@@ -58,7 +58,7 @@ const ensurePackageIsCorrectVersion = (
|
|
|
58
58
|
file: packageJsonPath,
|
|
59
59
|
message: `Expected dependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDependencyValue}' instead.`,
|
|
60
60
|
fixer: () =>
|
|
61
|
-
mutateJson<PackageJson>(packageJsonPath, (input) => {
|
|
61
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
62
62
|
input.dependencies![dependencyPackageName] = expectedPackageDependencyValue;
|
|
63
63
|
return input;
|
|
64
64
|
}),
|
|
@@ -76,7 +76,7 @@ const ensurePackageIsCorrectVersion = (
|
|
|
76
76
|
file: packageJsonPath,
|
|
77
77
|
message: `Expected devDependency on ${dependencyPackageName} to match version defined in monorepolint configuration '${expectedPackageDependencyValue}', got '${actualPackageDevDependencyValue}' instead`,
|
|
78
78
|
fixer: () =>
|
|
79
|
-
mutateJson<PackageJson>(packageJsonPath, (input) => {
|
|
79
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
80
80
|
input.devDependencies![dependencyPackageName] = expectedPackageDependencyValue;
|
|
81
81
|
return input;
|
|
82
82
|
}),
|
package/src/fileContents.ts
CHANGED
|
@@ -7,31 +7,29 @@
|
|
|
7
7
|
|
|
8
8
|
import { Context } from "@monorepolint/core";
|
|
9
9
|
import { RuleModule } from "@monorepolint/core";
|
|
10
|
-
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "fs";
|
|
11
10
|
import diff from "jest-diff";
|
|
12
11
|
import * as path from "path";
|
|
13
12
|
import * as r from "runtypes";
|
|
14
|
-
import { makeDirectoryRecursively } from "./util/makeDirectory";
|
|
15
13
|
|
|
16
14
|
const Options = r.Union(
|
|
17
15
|
r.Record({
|
|
18
16
|
file: r.String,
|
|
19
17
|
generator: r.Function,
|
|
20
|
-
template: r.Undefined,
|
|
21
|
-
templateFile: r.Undefined,
|
|
18
|
+
template: r.Undefined.optional(),
|
|
19
|
+
templateFile: r.Undefined.optional(),
|
|
22
20
|
}),
|
|
23
21
|
|
|
24
22
|
r.Record({
|
|
25
23
|
file: r.String,
|
|
26
|
-
generator: r.Undefined,
|
|
24
|
+
generator: r.Undefined.optional(),
|
|
27
25
|
template: r.String,
|
|
28
|
-
templateFile: r.Undefined,
|
|
26
|
+
templateFile: r.Undefined.optional(),
|
|
29
27
|
}),
|
|
30
28
|
|
|
31
29
|
r.Record({
|
|
32
30
|
file: r.String,
|
|
33
|
-
generator: r.Undefined,
|
|
34
|
-
template: r.Undefined,
|
|
31
|
+
generator: r.Undefined.optional(),
|
|
32
|
+
template: r.Undefined.optional(),
|
|
35
33
|
templateFile: r.String,
|
|
36
34
|
})
|
|
37
35
|
);
|
|
@@ -41,22 +39,21 @@ type Options = r.Static<typeof Options>;
|
|
|
41
39
|
export const fileContents = {
|
|
42
40
|
check: function expectFileContents(context: Context, opts: Options) {
|
|
43
41
|
const fullPath = path.join(context.packageDir, opts.file);
|
|
44
|
-
const
|
|
45
|
-
const expectedContent = generator(context);
|
|
42
|
+
const expectedContent = getExpectedContents(context, opts);
|
|
46
43
|
|
|
47
|
-
const pathExists =
|
|
48
|
-
const actualContent = pathExists ?
|
|
44
|
+
const pathExists = context.host.exists(fullPath);
|
|
45
|
+
const actualContent = pathExists ? context.host.readFile(fullPath, { encoding: "utf-8" }) : undefined;
|
|
49
46
|
if (actualContent !== expectedContent) {
|
|
50
47
|
context.addError({
|
|
51
48
|
file: fullPath,
|
|
52
49
|
message: "Expect file contents to match",
|
|
53
50
|
longMessage: diff(expectedContent, actualContent, { expand: true }),
|
|
54
51
|
fixer: () => {
|
|
55
|
-
if (expectedContent === undefined
|
|
56
|
-
|
|
52
|
+
if (expectedContent === undefined) {
|
|
53
|
+
if (pathExists) context.host.deleteFile(fullPath);
|
|
57
54
|
} else {
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
context.host.mkdir(path.dirname(fullPath), { recursive: true });
|
|
56
|
+
context.host.writeFile(fullPath, expectedContent, { encoding: "utf-8" });
|
|
60
57
|
}
|
|
61
58
|
},
|
|
62
59
|
});
|
|
@@ -65,25 +62,30 @@ export const fileContents = {
|
|
|
65
62
|
optionsRuntype: Options,
|
|
66
63
|
} as RuleModule<typeof Options>;
|
|
67
64
|
|
|
68
|
-
|
|
65
|
+
const optionsCache = new Map<Options, ((context: Context) => string | undefined) | string | undefined>();
|
|
66
|
+
|
|
67
|
+
function getExpectedContents(context: Context, opts: Options) {
|
|
68
|
+
// we need to use has because undefined is a valid value in the cache
|
|
69
|
+
if (optionsCache.has(opts)) {
|
|
70
|
+
const cachedEntry = optionsCache.get(opts);
|
|
71
|
+
if (cachedEntry && typeof cachedEntry === "function") {
|
|
72
|
+
return cachedEntry(context);
|
|
73
|
+
}
|
|
74
|
+
return cachedEntry;
|
|
75
|
+
}
|
|
76
|
+
|
|
69
77
|
if (opts.generator) {
|
|
70
|
-
|
|
78
|
+
optionsCache.set(opts, opts.generator);
|
|
79
|
+
return opts.generator(context) as string | undefined; // we have no guarentee its the right kind of function
|
|
71
80
|
} else if (opts.templateFile) {
|
|
72
81
|
const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
|
|
73
82
|
const fullPath = path.resolve(workspacePackageDir, opts.templateFile);
|
|
74
|
-
const template =
|
|
83
|
+
const template = context.host.readFile(fullPath, { encoding: "utf-8" });
|
|
75
84
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return makeGenerator(opts.template);
|
|
85
|
+
optionsCache.set(opts, template);
|
|
86
|
+
return template;
|
|
79
87
|
} else {
|
|
80
|
-
|
|
88
|
+
optionsCache.set(opts, opts.template);
|
|
89
|
+
return opts.template;
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
|
-
|
|
84
|
-
function makeGenerator(template: string) {
|
|
85
|
-
// tslint:disable-next-line:variable-name
|
|
86
|
-
return function generator(_context: Context) {
|
|
87
|
-
return template;
|
|
88
|
-
};
|
|
89
|
-
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
9
|
+
import { Host, mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import resolvePackagePath from "resolve-package-path";
|
|
12
12
|
import * as r from "runtypes";
|
|
@@ -398,6 +398,7 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
398
398
|
dependencyType: "peerDependencies",
|
|
399
399
|
dependencyName: peerDependencyName,
|
|
400
400
|
version: mostStrictPeerRequirement.range,
|
|
401
|
+
host: context.host,
|
|
401
402
|
}),
|
|
402
403
|
});
|
|
403
404
|
}
|
|
@@ -423,6 +424,7 @@ function checkSatisfyPeerDependencies(context: Context, opts: Options) {
|
|
|
423
424
|
dependencyType: "peerDependencies",
|
|
424
425
|
dependencyName: peerDependencyName,
|
|
425
426
|
version: mostStrictPeerRequirement.range,
|
|
427
|
+
host: context.host,
|
|
426
428
|
}),
|
|
427
429
|
});
|
|
428
430
|
}
|
|
@@ -717,14 +719,16 @@ function getAddDependencyTypeFixer({
|
|
|
717
719
|
dependencyType,
|
|
718
720
|
dependencyName,
|
|
719
721
|
version,
|
|
722
|
+
host,
|
|
720
723
|
}: {
|
|
721
724
|
packageJsonPath: string;
|
|
722
725
|
dependencyType: IDependencyType;
|
|
723
726
|
dependencyName: string;
|
|
724
727
|
version: string;
|
|
728
|
+
host: Host;
|
|
725
729
|
}) {
|
|
726
730
|
return () => {
|
|
727
|
-
mutateJson<PackageJson>(packageJsonPath, (packageJson) => {
|
|
731
|
+
mutateJson<PackageJson>(packageJsonPath, host, (packageJson) => {
|
|
728
732
|
if (packageJson[dependencyType] == null) {
|
|
729
733
|
packageJson[dependencyType] = {};
|
|
730
734
|
}
|
package/src/packageEntry.ts
CHANGED
|
@@ -37,7 +37,7 @@ export const Options = r.Union(
|
|
|
37
37
|
|
|
38
38
|
export type Options = r.Static<typeof Options>;
|
|
39
39
|
|
|
40
|
-
export const packageEntry = {
|
|
40
|
+
export const packageEntry: RuleModule<typeof Options> = {
|
|
41
41
|
check: function expectPackageEntry(context: Context, options: Options) {
|
|
42
42
|
const packageJson = context.getPackageJson();
|
|
43
43
|
|
|
@@ -53,10 +53,10 @@ export const packageEntry = {
|
|
|
53
53
|
) {
|
|
54
54
|
context.addError({
|
|
55
55
|
file: context.getPackageJsonPath(),
|
|
56
|
-
message:
|
|
56
|
+
message: createStandardizedEntryErrorMessage(key),
|
|
57
57
|
longMessage: entryDiff,
|
|
58
58
|
fixer: () => {
|
|
59
|
-
mutateJson<PackageJson>(context.getPackageJsonPath(), (input) => {
|
|
59
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
60
60
|
input[key] = value;
|
|
61
61
|
return input;
|
|
62
62
|
});
|
|
@@ -71,11 +71,19 @@ export const packageEntry = {
|
|
|
71
71
|
if (packageJson[key] === undefined) {
|
|
72
72
|
context.addError({
|
|
73
73
|
file: context.getPackageJsonPath(),
|
|
74
|
-
message:
|
|
74
|
+
message: createExpectedEntryErrorMessage(key),
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
optionsRuntype: Options,
|
|
81
|
-
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export function createStandardizedEntryErrorMessage(key: string) {
|
|
84
|
+
return `Expected standardized entry for '${key}'`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createExpectedEntryErrorMessage(key: string) {
|
|
88
|
+
return `Expected entry for '${key}' to exist`;
|
|
89
|
+
}
|
package/src/packageOrder.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import { writeJson } from "@monorepolint/utils";
|
|
10
9
|
import diff from "jest-diff";
|
|
11
10
|
import * as r from "runtypes";
|
|
12
11
|
|
|
@@ -73,7 +72,7 @@ export const packageOrder = {
|
|
|
73
72
|
expectedPackageJson[key] = packageJson[key];
|
|
74
73
|
});
|
|
75
74
|
|
|
76
|
-
writeJson(packagePath, expectedPackageJson);
|
|
75
|
+
context.host.writeJson(packagePath, expectedPackageJson);
|
|
77
76
|
},
|
|
78
77
|
});
|
|
79
78
|
}
|
package/src/packageScript.ts
CHANGED
|
@@ -39,7 +39,7 @@ export const packageScript = {
|
|
|
39
39
|
file: context.getPackageJsonPath(),
|
|
40
40
|
message: MSG_NO_SCRIPTS_BLOCK,
|
|
41
41
|
fixer: () => {
|
|
42
|
-
mutateJson<PackageJson>(context.getPackageJsonPath(), (input) => {
|
|
42
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
43
43
|
input.scripts = {};
|
|
44
44
|
return input;
|
|
45
45
|
});
|
|
@@ -75,7 +75,7 @@ export const packageScript = {
|
|
|
75
75
|
if (fixValue !== false && (fixValue !== undefined || fixToEmpty === true)) {
|
|
76
76
|
const q = fixValue;
|
|
77
77
|
fixer = () => {
|
|
78
|
-
mutateJson<PackageJson>(context.getPackageJsonPath(), (input) => {
|
|
78
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
79
79
|
if (fixToEmpty && q === undefined) {
|
|
80
80
|
delete input.scripts![name];
|
|
81
81
|
} else {
|
package/src/requireDependency.ts
CHANGED
|
@@ -39,7 +39,7 @@ export const requireDependency = {
|
|
|
39
39
|
file: packageJsonPath,
|
|
40
40
|
message: `No ${type} block, cannot add required ${type}.`,
|
|
41
41
|
fixer: () => {
|
|
42
|
-
mutateJson<PackageJson>(packageJsonPath, (input) => {
|
|
42
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
43
43
|
input[type] = options[type];
|
|
44
44
|
return input;
|
|
45
45
|
});
|
|
@@ -55,7 +55,7 @@ export const requireDependency = {
|
|
|
55
55
|
message: `Expected dependency ${dep}@${version}`,
|
|
56
56
|
longMessage: diff(`${dep}@${version}\n`, `${dep}@${packageJson[type][dep] || "missing"}\n`)!,
|
|
57
57
|
fixer: () => {
|
|
58
|
-
mutateJson<PackageJson>(packageJsonPath, (input) => {
|
|
58
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
59
59
|
input[type] = { ...input[type], [dep]: version };
|
|
60
60
|
return input;
|
|
61
61
|
});
|
package/src/standardTsconfig.ts
CHANGED
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, RuleModule } from "@monorepolint/core";
|
|
9
|
-
import {
|
|
9
|
+
import { matchesAnyGlob } from "@monorepolint/utils";
|
|
10
10
|
import diff from "jest-diff";
|
|
11
|
-
import minimatch from "minimatch";
|
|
12
11
|
import * as path from "path";
|
|
13
12
|
import * as r from "runtypes";
|
|
14
13
|
|
|
@@ -48,7 +47,9 @@ export const standardTsconfig = {
|
|
|
48
47
|
const generator = getGenerator(context, opts);
|
|
49
48
|
const expectedContent = generator(context);
|
|
50
49
|
|
|
51
|
-
const actualContent =
|
|
50
|
+
const actualContent = context.host.exists(fullPath)
|
|
51
|
+
? context.host.readFile(fullPath, { encoding: "utf-8" })
|
|
52
|
+
: undefined;
|
|
52
53
|
|
|
53
54
|
if (expectedContent === undefined) {
|
|
54
55
|
context.addWarning({
|
|
@@ -64,7 +65,9 @@ export const standardTsconfig = {
|
|
|
64
65
|
message: "Expect file contents to match",
|
|
65
66
|
longMessage: diff(expectedContent, actualContent, { expand: true }),
|
|
66
67
|
fixer: () => {
|
|
67
|
-
|
|
68
|
+
context.host.writeFile(fullPath, expectedContent, {
|
|
69
|
+
encoding: "utf-8",
|
|
70
|
+
});
|
|
68
71
|
},
|
|
69
72
|
});
|
|
70
73
|
}
|
|
@@ -78,7 +81,7 @@ function getGenerator(context: Context, opts: Options) {
|
|
|
78
81
|
} else if (opts.templateFile) {
|
|
79
82
|
const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
|
|
80
83
|
const fullPath = path.resolve(workspacePackageDir, opts.templateFile);
|
|
81
|
-
const template = JSON.parse(
|
|
84
|
+
const template = JSON.parse(context.host.readFile(fullPath, { encoding: "utf-8" }));
|
|
82
85
|
|
|
83
86
|
return makeGenerator(template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
|
|
84
87
|
} else if (opts.template) {
|
|
@@ -90,8 +93,8 @@ function getGenerator(context: Context, opts: Options) {
|
|
|
90
93
|
|
|
91
94
|
function makeGenerator(
|
|
92
95
|
template: any,
|
|
93
|
-
excludedReferences: ReadonlyArray<string>
|
|
94
|
-
additionalReferences: ReadonlyArray<string>
|
|
96
|
+
excludedReferences: ReadonlyArray<string> | undefined,
|
|
97
|
+
additionalReferences: ReadonlyArray<string> | undefined,
|
|
95
98
|
tsconfigReferenceFile?: string
|
|
96
99
|
) {
|
|
97
100
|
return function generator(context: Context) {
|
|
@@ -105,24 +108,24 @@ function makeGenerator(
|
|
|
105
108
|
const packageJson = context.getPackageJson();
|
|
106
109
|
const deps = [...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.devDependencies || {})];
|
|
107
110
|
|
|
108
|
-
deps
|
|
109
|
-
.
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
.forEach((packageName) => {
|
|
113
|
-
const packageDir = nameToDirectory.get(packageName)!;
|
|
111
|
+
for (const dep of deps) {
|
|
112
|
+
const packageDir = nameToDirectory.get(dep);
|
|
113
|
+
if (packageDir !== undefined && (excludedReferences === undefined || matchesAnyGlob(dep, excludedReferences))) {
|
|
114
114
|
const absoluteReferencePath =
|
|
115
115
|
tsconfigReferenceFile !== undefined ? path.join(packageDir, tsconfigReferenceFile) : packageDir;
|
|
116
116
|
template.references.push({
|
|
117
117
|
path: path.relative(context.packageDir, absoluteReferencePath),
|
|
118
118
|
});
|
|
119
|
-
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
120
121
|
|
|
121
|
-
additionalReferences
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
if (additionalReferences) {
|
|
123
|
+
for (const additionalReference of additionalReferences) {
|
|
124
|
+
template.references.push({
|
|
125
|
+
path: additionalReference,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
126
129
|
|
|
127
130
|
return JSON.stringify(template, undefined, 2) + "\n";
|
|
128
131
|
};
|
package/src/util/checkAlpha.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context } from "@monorepolint/core";
|
|
9
|
-
import { writeJson } from "@monorepolint/utils";
|
|
10
9
|
import diff from "jest-diff";
|
|
11
10
|
|
|
12
11
|
export function checkAlpha(
|
|
@@ -28,7 +27,7 @@ export function checkAlpha(
|
|
|
28
27
|
if (!arrayOrderCompare(actualOrder, expectedOrder)) {
|
|
29
28
|
context.addError({
|
|
30
29
|
file: packagePath,
|
|
31
|
-
message:
|
|
30
|
+
message: createIncorrectOrderErrorMessage(block, packageJson.name!),
|
|
32
31
|
longMessage: diff(expectedOrder, actualOrder, { expand: true }),
|
|
33
32
|
fixer: () => {
|
|
34
33
|
const expectedDependencies: Record<string, string> = {};
|
|
@@ -39,7 +38,7 @@ export function checkAlpha(
|
|
|
39
38
|
|
|
40
39
|
const newPackageJson = { ...packageJson };
|
|
41
40
|
newPackageJson[block] = expectedDependencies;
|
|
42
|
-
writeJson(packagePath, newPackageJson);
|
|
41
|
+
context.host.writeJson(packagePath, newPackageJson);
|
|
43
42
|
},
|
|
44
43
|
});
|
|
45
44
|
}
|
|
@@ -54,3 +53,7 @@ function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
|
|
54
53
|
|
|
55
54
|
return true;
|
|
56
55
|
}
|
|
56
|
+
|
|
57
|
+
export function createIncorrectOrderErrorMessage(block: string, packageName: string) {
|
|
58
|
+
return `Incorrect order of ${block} in ${packageName}'s package.json`;
|
|
59
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @license Copyright 2019 Palantir Technologies, Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { PackageJson } from "@monorepolint/utils";
|
|
5
|
+
import { Host, PackageJson } from "@monorepolint/utils";
|
|
6
6
|
import path from "path";
|
|
7
7
|
import resolvePackagePath from "resolve-package-path";
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ export interface IPackageDependencyGraphNode {
|
|
|
19
19
|
/** Service abstraction for constructing and traversing package dependency graphs. */
|
|
20
20
|
export interface IPackageDependencyGraphService {
|
|
21
21
|
/** Construct a graph of package dependencies. */
|
|
22
|
-
buildDependencyGraph(packageJsonPath: string, maxDepth?: number): IPackageDependencyGraphNode;
|
|
22
|
+
buildDependencyGraph(packageJsonPath: string, host: Host, maxDepth?: number): IPackageDependencyGraphNode;
|
|
23
23
|
|
|
24
24
|
/** Traverse a package dependency graph. */
|
|
25
25
|
traverse(
|
|
@@ -34,15 +34,18 @@ export interface IPackageDependencyGraphService {
|
|
|
34
34
|
/** Default implementation of the package dependency graph service. */
|
|
35
35
|
export class PackageDependencyGraphService implements IPackageDependencyGraphService {
|
|
36
36
|
/** Construct a graph of package dependencies and return the root node. */
|
|
37
|
-
public buildDependencyGraph(
|
|
37
|
+
public buildDependencyGraph(
|
|
38
|
+
startPackageJsonPath: string,
|
|
39
|
+
host: Host,
|
|
40
|
+
maxDepth?: number
|
|
41
|
+
): IPackageDependencyGraphNode {
|
|
38
42
|
const nodes = new Map<string, IPackageDependencyGraphNode>();
|
|
39
|
-
|
|
40
43
|
const visit = (packageJsonPath: string, currentDepth: number): IPackageDependencyGraphNode => {
|
|
41
44
|
if (nodes.has(packageJsonPath)) {
|
|
42
45
|
return nodes.get(packageJsonPath)!;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const packageJson: PackageJson =
|
|
48
|
+
const packageJson: PackageJson = host.readJson(packageJsonPath);
|
|
46
49
|
const node: IPackageDependencyGraphNode = {
|
|
47
50
|
packageJson,
|
|
48
51
|
dependencies: new Map<string, IPackageDependencyGraphNode>(),
|