@monorepolint/rules 0.5.0-alpha.10 → 0.5.0-alpha.103
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/.turbo/turbo-clean.log +4 -0
- package/.turbo/turbo-compile-typescript.log +4 -0
- package/.turbo/turbo-lint.log +107 -0
- package/.turbo/turbo-test.log +631 -0
- package/.turbo/turbo-transpile-typescript.log +18 -0
- package/build/js/index.cjs +1491 -0
- package/build/js/index.cjs.map +1 -0
- package/build/js/index.js +1433 -0
- package/build/js/index.js.map +1 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/{lib/__tests__/utils.d.ts → build/types/__tests__/alphabeticalScripts.spec.d.ts} +2 -2
- package/build/types/__tests__/alphabeticalScripts.spec.d.ts.map +1 -0
- package/build/types/__tests__/bannedDependencies.spec.d.ts +2 -0
- package/build/types/__tests__/bannedDependencies.spec.d.ts.map +1 -0
- package/{lib → build/types}/__tests__/consistentDependencies.spec.d.ts +0 -0
- package/build/types/__tests__/consistentDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/consistentVersions.spec.d.ts +8 -0
- package/build/types/__tests__/consistentVersions.spec.d.ts.map +1 -0
- package/build/types/__tests__/fileContents.spec.d.ts +8 -0
- package/build/types/__tests__/fileContents.spec.d.ts.map +1 -0
- package/build/types/__tests__/mustSatisfyPeerDependencies.spec.d.ts +8 -0
- package/build/types/__tests__/mustSatisfyPeerDependencies.spec.d.ts.map +1 -0
- package/build/types/__tests__/nestedWorkspaces.spec.d.ts +2 -0
- package/build/types/__tests__/nestedWorkspaces.spec.d.ts.map +1 -0
- package/{lib → build/types}/__tests__/packageEntry.spec.d.ts +0 -0
- package/build/types/__tests__/packageEntry.spec.d.ts.map +1 -0
- package/{lib → build/types}/__tests__/packageOrder.spec.d.ts +0 -0
- package/build/types/__tests__/packageOrder.spec.d.ts.map +1 -0
- package/{lib → build/types}/__tests__/packageScript.spec.d.ts +0 -0
- package/build/types/__tests__/packageScript.spec.d.ts.map +1 -0
- package/build/types/__tests__/requireDependency.spec.d.ts +2 -0
- package/build/types/__tests__/requireDependency.spec.d.ts.map +1 -0
- package/build/types/__tests__/utils.d.ts +81 -0
- package/build/types/__tests__/utils.d.ts.map +1 -0
- package/build/types/alphabeticalDependencies.d.ts +23 -0
- package/build/types/alphabeticalDependencies.d.ts.map +1 -0
- package/build/types/alphabeticalScripts.d.ts +23 -0
- package/build/types/alphabeticalScripts.d.ts.map +1 -0
- package/build/types/bannedDependencies.d.ts +134 -0
- package/build/types/bannedDependencies.d.ts.map +1 -0
- package/build/types/consistentDependencies.d.ts +38 -0
- package/build/types/consistentDependencies.d.ts.map +1 -0
- package/build/types/consistentVersions.d.ts +47 -0
- package/build/types/consistentVersions.d.ts.map +1 -0
- package/build/types/fileContents.d.ts +111 -0
- package/build/types/fileContents.d.ts.map +1 -0
- package/build/types/index.d.ts +20 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/mustSatisfyPeerDependencies.d.ts +721 -0
- package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -0
- package/build/types/nestedWorkspaces.d.ts +24 -0
- package/build/types/nestedWorkspaces.d.ts.map +1 -0
- package/build/types/packageEntry.d.ts +115 -0
- package/build/types/packageEntry.d.ts.map +1 -0
- package/build/types/packageOrder.d.ts +33 -0
- package/build/types/packageOrder.d.ts.map +1 -0
- package/build/types/packageScript.d.ts +89 -0
- package/build/types/packageScript.d.ts.map +1 -0
- package/build/types/requireDependency.d.ts +99 -0
- package/build/types/requireDependency.d.ts.map +1 -0
- package/build/types/standardTsconfig.d.ts +113 -0
- package/build/types/standardTsconfig.d.ts.map +1 -0
- package/build/types/util/checkAlpha.d.ts +10 -0
- package/build/types/util/checkAlpha.d.ts.map +1 -0
- package/build/types/util/createNewRuleConversion.d.ts +30 -0
- package/build/types/util/createNewRuleConversion.d.ts.map +1 -0
- package/build/types/util/makeDirectory.d.ts +8 -0
- package/build/types/util/makeDirectory.d.ts.map +1 -0
- package/build/types/util/packageDependencyGraphService.d.ts +37 -0
- package/build/types/util/packageDependencyGraphService.d.ts.map +1 -0
- package/{jest.config.js → jest.config.cjs} +0 -0
- package/package.json +39 -20
- package/src/__tests__/alphabeticalScripts.spec.ts +76 -0
- package/src/__tests__/bannedDependencies.spec.ts +191 -0
- package/src/__tests__/consistentDependencies.spec.ts +41 -27
- package/src/__tests__/consistentVersions.spec.ts +224 -0
- package/src/__tests__/fileContents.spec.ts +75 -0
- package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +1189 -0
- package/src/__tests__/nestedWorkspaces.spec.ts +153 -0
- package/src/__tests__/packageEntry.spec.ts +99 -31
- package/src/__tests__/packageOrder.spec.ts +48 -41
- package/src/__tests__/packageScript.spec.ts +66 -56
- package/src/__tests__/requireDependency.spec.ts +152 -0
- package/src/__tests__/utils.ts +115 -11
- package/src/alphabeticalDependencies.ts +6 -48
- package/src/alphabeticalScripts.ts +21 -0
- package/src/bannedDependencies.ts +135 -44
- package/src/consistentDependencies.ts +38 -14
- package/src/consistentVersions.ts +142 -0
- package/src/fileContents.ts +35 -30
- package/src/index.ts +13 -8
- package/src/mustSatisfyPeerDependencies.ts +748 -0
- package/src/nestedWorkspaces.ts +61 -0
- package/src/packageEntry.ts +72 -27
- package/src/packageOrder.ts +13 -9
- package/src/packageScript.ts +13 -15
- package/src/requireDependency.ts +71 -0
- package/src/standardTsconfig.ts +49 -24
- package/src/util/checkAlpha.ts +59 -0
- package/src/util/createNewRuleConversion.ts +38 -0
- package/src/util/makeDirectory.ts +24 -0
- package/src/util/packageDependencyGraphService.ts +114 -0
- package/tsconfig.json +10 -2
- package/lib/__tests__/consistentDependencies.spec.d.ts.map +0 -1
- package/lib/__tests__/consistentDependencies.spec.js +0 -108
- package/lib/__tests__/consistentDependencies.spec.js.map +0 -1
- package/lib/__tests__/packageEntry.spec.d.ts.map +0 -1
- package/lib/__tests__/packageEntry.spec.js +0 -99
- package/lib/__tests__/packageEntry.spec.js.map +0 -1
- package/lib/__tests__/packageOrder.spec.d.ts.map +0 -1
- package/lib/__tests__/packageOrder.spec.js +0 -115
- package/lib/__tests__/packageOrder.spec.js.map +0 -1
- package/lib/__tests__/packageScript.spec.d.ts.map +0 -1
- package/lib/__tests__/packageScript.spec.js +0 -172
- package/lib/__tests__/packageScript.spec.js.map +0 -1
- package/lib/__tests__/utils.d.ts.map +0 -1
- package/lib/__tests__/utils.js +0 -23
- package/lib/__tests__/utils.js.map +0 -1
- package/lib/alphabeticalDependencies.d.ts +0 -10
- package/lib/alphabeticalDependencies.d.ts.map +0 -1
- package/lib/alphabeticalDependencies.js +0 -56
- package/lib/alphabeticalDependencies.js.map +0 -1
- package/lib/bannedDependencies.d.ts +0 -15
- package/lib/bannedDependencies.d.ts.map +0 -1
- package/lib/bannedDependencies.js +0 -57
- package/lib/bannedDependencies.js.map +0 -1
- package/lib/consistentDependencies.d.ts +0 -10
- package/lib/consistentDependencies.d.ts.map +0 -1
- package/lib/consistentDependencies.js +0 -57
- package/lib/consistentDependencies.js.map +0 -1
- package/lib/fileContents.d.ts +0 -25
- package/lib/fileContents.d.ts.map +0 -1
- package/lib/fileContents.js +0 -77
- package/lib/fileContents.js.map +0 -1
- package/lib/index.d.ts +0 -15
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js +0 -25
- package/lib/index.js.map +0 -1
- package/lib/packageEntry.d.ts +0 -16
- package/lib/packageEntry.d.ts.map +0 -1
- package/lib/packageEntry.js +0 -40
- package/lib/packageEntry.js.map +0 -1
- package/lib/packageOrder.d.ts +0 -12
- package/lib/packageOrder.d.ts.map +0 -1
- package/lib/packageOrder.js +0 -103
- package/lib/packageOrder.js.map +0 -1
- package/lib/packageScript.d.ts +0 -25
- package/lib/packageScript.d.ts.map +0 -1
- package/lib/packageScript.js +0 -89
- package/lib/packageScript.js.map +0 -1
- package/lib/standardTsconfig.d.ts +0 -33
- package/lib/standardTsconfig.d.ts.map +0 -1
- package/lib/standardTsconfig.js +0 -98
- package/lib/standardTsconfig.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -2439
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2019 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
|
+
import * as globby from "globby";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import * as r from "runtypes";
|
|
12
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
13
|
+
export const Options = r.Undefined;
|
|
14
|
+
|
|
15
|
+
type Options = r.Static<typeof Options>;
|
|
16
|
+
|
|
17
|
+
// Enforce that the root package.json contains all of the workspaces in the repo (including nested packages)
|
|
18
|
+
export const nestedWorkspaces: RuleModule<typeof Options> = {
|
|
19
|
+
check: (context: Context) => {
|
|
20
|
+
const rootPackageJson = context.getWorkspaceContext().getPackageJson();
|
|
21
|
+
|
|
22
|
+
// Expand a set of globs covering all package.json files in the entire repo (except the root)
|
|
23
|
+
const packageJsonPaths = globby.globbySync(["*/**/package.json", "!**/node_modules/**"]);
|
|
24
|
+
|
|
25
|
+
const workspaces = Array.isArray(rootPackageJson.workspaces)
|
|
26
|
+
? rootPackageJson.workspaces
|
|
27
|
+
: rootPackageJson.workspaces !== undefined
|
|
28
|
+
? rootPackageJson.workspaces.packages
|
|
29
|
+
: undefined;
|
|
30
|
+
|
|
31
|
+
if (workspaces === undefined && packageJsonPaths.length > 0) {
|
|
32
|
+
context.addError({
|
|
33
|
+
file: context.getPackageJsonPath(),
|
|
34
|
+
message: 'The "workspace" field is missing, even though there are workspaces in the repository.',
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Build a set of globs for each package.json that exists in packages specified by a workspace.
|
|
40
|
+
const workspacePackageJsons = (workspaces || []).map((item) => `${item}/package.json`);
|
|
41
|
+
|
|
42
|
+
// Expand the globs to get an array of all package.json files that are in packages specified by a workspace.
|
|
43
|
+
const expandedWorkspacesGlobs = globby.globbySync([...workspacePackageJsons, "!**/node_modules/**"]);
|
|
44
|
+
|
|
45
|
+
// Ensure there are no package.jsons which are not included in the globbed workspaces set
|
|
46
|
+
const difference = packageJsonPaths.filter((packageJsonPath) => !expandedWorkspacesGlobs.includes(packageJsonPath));
|
|
47
|
+
|
|
48
|
+
if (difference.length !== 0) {
|
|
49
|
+
const differencesList = difference.map((packageJsonPath) => path.dirname(packageJsonPath)).join(", ");
|
|
50
|
+
context.addError({
|
|
51
|
+
file: context.getPackageJsonPath(),
|
|
52
|
+
message:
|
|
53
|
+
`The "workspace" field is missing one or more values: ${differencesList}. ` +
|
|
54
|
+
'You may be able to use a glob to avoid listing each workspace individually, e.g. "packages/nested-workspace/*".',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
optionsRuntype: Options,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const NestedWorkspaces = createNewRuleConversion("NestedWorkspaces", nestedWorkspaces);
|
package/src/packageEntry.ts
CHANGED
|
@@ -5,42 +5,87 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Context, RuleModule } from "@monorepolint/
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
9
|
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
|
-
import diff from "jest-diff";
|
|
10
|
+
import { diff } from "jest-diff";
|
|
11
11
|
import * as r from "runtypes";
|
|
12
|
-
|
|
13
|
-
export const Options = r.
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
13
|
+
export const Options = r.Union(
|
|
14
|
+
r
|
|
15
|
+
.Record({
|
|
16
|
+
entries: r.Dictionary(r.Unknown), // string => unknown, enforces existence of keys and their values
|
|
17
|
+
})
|
|
18
|
+
.And(
|
|
19
|
+
r.Partial({
|
|
20
|
+
entriesExist: r.Undefined,
|
|
21
|
+
})
|
|
22
|
+
),
|
|
23
|
+
r
|
|
24
|
+
.Record({
|
|
25
|
+
entriesExist: r.Array(r.String), // enforces existence of keys, but not values
|
|
26
|
+
})
|
|
27
|
+
.And(
|
|
28
|
+
r.Partial({
|
|
29
|
+
entries: r.Undefined,
|
|
30
|
+
})
|
|
31
|
+
),
|
|
32
|
+
r.Record({
|
|
33
|
+
entries: r.Dictionary(r.Unknown), // string => unknown, enforces existence of keys and their values
|
|
34
|
+
entriesExist: r.Array(r.String),
|
|
35
|
+
})
|
|
36
|
+
);
|
|
16
37
|
|
|
17
38
|
export type Options = r.Static<typeof Options>;
|
|
18
39
|
|
|
19
|
-
export const packageEntry = {
|
|
40
|
+
export const packageEntry: RuleModule<typeof Options> = {
|
|
20
41
|
check: function expectPackageEntry(context: Context, options: Options) {
|
|
21
42
|
const packageJson = context.getPackageJson();
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
if (options.entries) {
|
|
45
|
+
for (const key of Object.keys(options.entries)) {
|
|
46
|
+
const value = options.entries[key];
|
|
47
|
+
|
|
48
|
+
const entryDiff = diff(JSON.stringify(value) + "\n", (JSON.stringify(packageJson[key]) || "") + "\n");
|
|
49
|
+
if (
|
|
50
|
+
(typeof value !== "object" && value !== packageJson[key]) ||
|
|
51
|
+
entryDiff == null ||
|
|
52
|
+
!entryDiff.includes("Compared values have no visual difference")
|
|
53
|
+
) {
|
|
54
|
+
context.addError({
|
|
55
|
+
file: context.getPackageJsonPath(),
|
|
56
|
+
message: createStandardizedEntryErrorMessage(key),
|
|
57
|
+
longMessage: entryDiff,
|
|
58
|
+
fixer: () => {
|
|
59
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
60
|
+
input[key] = value;
|
|
61
|
+
return input;
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (options.entriesExist) {
|
|
70
|
+
for (const key of options.entriesExist) {
|
|
71
|
+
if (packageJson[key] === undefined) {
|
|
72
|
+
context.addError({
|
|
73
|
+
file: context.getPackageJsonPath(),
|
|
74
|
+
message: createExpectedEntryErrorMessage(key),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
42
77
|
}
|
|
43
78
|
}
|
|
44
79
|
},
|
|
45
80
|
optionsRuntype: Options,
|
|
46
|
-
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const PackageEntry = createNewRuleConversion("PackageEntry", packageEntry);
|
|
84
|
+
|
|
85
|
+
export function createStandardizedEntryErrorMessage(key: string) {
|
|
86
|
+
return `Expected standardized entry for '${key}'`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function createExpectedEntryErrorMessage(key: string) {
|
|
90
|
+
return `Expected entry for '${key}' to exist`;
|
|
91
|
+
}
|
package/src/packageOrder.ts
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Context, RuleModule } from "@monorepolint/
|
|
9
|
-
import {
|
|
10
|
-
import diff from "jest-diff";
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
|
+
import { diff } from "jest-diff";
|
|
11
10
|
import * as r from "runtypes";
|
|
12
|
-
|
|
11
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
13
12
|
type OrderFunction = (context: Context) => (a: string, b: string) => number;
|
|
14
13
|
|
|
15
14
|
const Options = r
|
|
@@ -28,9 +27,12 @@ const defaultKeyOrder = [
|
|
|
28
27
|
"contributors",
|
|
29
28
|
"url",
|
|
30
29
|
"license",
|
|
30
|
+
"type",
|
|
31
|
+
"exports",
|
|
31
32
|
"private",
|
|
32
33
|
"engines",
|
|
33
34
|
"bin",
|
|
35
|
+
"types",
|
|
34
36
|
"main",
|
|
35
37
|
"module",
|
|
36
38
|
"typings",
|
|
@@ -56,10 +58,10 @@ export const packageOrder = {
|
|
|
56
58
|
|
|
57
59
|
const order: string[] | OrderFunction = opts === undefined ? defaultKeyOrder : opts.order;
|
|
58
60
|
|
|
59
|
-
const
|
|
61
|
+
const comparator = isOrderFunction(order) ? order(context) : createComparator(order);
|
|
60
62
|
|
|
61
63
|
const actualOrder = Object.keys(packageJson);
|
|
62
|
-
const expectedOrder = actualOrder.slice().sort(
|
|
64
|
+
const expectedOrder = actualOrder.slice().sort(comparator); // sort mutates, so we need to copy the previous result
|
|
63
65
|
|
|
64
66
|
if (!arrayOrderCompare(actualOrder, expectedOrder)) {
|
|
65
67
|
context.addError({
|
|
@@ -69,11 +71,11 @@ export const packageOrder = {
|
|
|
69
71
|
fixer: () => {
|
|
70
72
|
const expectedPackageJson: Record<string, any> = {};
|
|
71
73
|
|
|
72
|
-
expectedOrder.forEach(key => {
|
|
74
|
+
expectedOrder.forEach((key) => {
|
|
73
75
|
expectedPackageJson[key] = packageJson[key];
|
|
74
76
|
});
|
|
75
77
|
|
|
76
|
-
writeJson(packagePath, expectedPackageJson);
|
|
78
|
+
context.host.writeJson(packagePath, expectedPackageJson);
|
|
77
79
|
},
|
|
78
80
|
});
|
|
79
81
|
}
|
|
@@ -81,6 +83,8 @@ export const packageOrder = {
|
|
|
81
83
|
optionsRuntype: Options,
|
|
82
84
|
} as RuleModule<typeof Options>;
|
|
83
85
|
|
|
86
|
+
export const PackageOrder = createNewRuleConversion("PackageOrder", packageOrder);
|
|
87
|
+
|
|
84
88
|
function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
|
85
89
|
for (let index = 0; index < a.length; index++) {
|
|
86
90
|
if (a[index] !== b[index]) {
|
|
@@ -91,7 +95,7 @@ function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
|
|
91
95
|
return true;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
function
|
|
98
|
+
function createComparator(order: ReadonlyArray<string>) {
|
|
95
99
|
return (a: string, b: string) => {
|
|
96
100
|
const aIndex = order.indexOf(a);
|
|
97
101
|
const bIndex = order.indexOf(b);
|
package/src/packageScript.ts
CHANGED
|
@@ -5,24 +5,20 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Context, RuleModule } from "@monorepolint/
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
9
|
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
|
-
import
|
|
10
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
11
|
+
import { diff } from "jest-diff";
|
|
11
12
|
import * as r from "runtypes";
|
|
12
13
|
|
|
13
14
|
export const Options = r.Record({
|
|
14
15
|
scripts: r.Dictionary(
|
|
15
16
|
r.Union(
|
|
16
17
|
r.String,
|
|
17
|
-
r
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
.And(
|
|
22
|
-
r.Partial({
|
|
23
|
-
fixValue: r.Union(r.String, r.Undefined, r.Literal(false)),
|
|
24
|
-
})
|
|
25
|
-
)
|
|
18
|
+
r.Record({
|
|
19
|
+
options: r.Array(r.String.Or(r.Undefined)),
|
|
20
|
+
fixValue: r.Union(r.String, r.Undefined, r.Literal(false)).optional(),
|
|
21
|
+
})
|
|
26
22
|
)
|
|
27
23
|
), // string => string
|
|
28
24
|
});
|
|
@@ -39,7 +35,7 @@ export const packageScript = {
|
|
|
39
35
|
file: context.getPackageJsonPath(),
|
|
40
36
|
message: MSG_NO_SCRIPTS_BLOCK,
|
|
41
37
|
fixer: () => {
|
|
42
|
-
mutateJson<PackageJson>(context.getPackageJsonPath(), input => {
|
|
38
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
43
39
|
input.scripts = {};
|
|
44
40
|
return input;
|
|
45
41
|
});
|
|
@@ -63,7 +59,7 @@ export const packageScript = {
|
|
|
63
59
|
}
|
|
64
60
|
allowedValues.add(q);
|
|
65
61
|
}
|
|
66
|
-
fixToEmpty =
|
|
62
|
+
fixToEmpty = Object.prototype.hasOwnProperty.call(value, "fixValue") && value.fixValue === undefined;
|
|
67
63
|
fixValue = value.fixValue;
|
|
68
64
|
}
|
|
69
65
|
|
|
@@ -75,7 +71,7 @@ export const packageScript = {
|
|
|
75
71
|
if (fixValue !== false && (fixValue !== undefined || fixToEmpty === true)) {
|
|
76
72
|
const q = fixValue;
|
|
77
73
|
fixer = () => {
|
|
78
|
-
mutateJson<PackageJson>(context.getPackageJsonPath(), input => {
|
|
74
|
+
mutateJson<PackageJson>(context.getPackageJsonPath(), context.host, (input) => {
|
|
79
75
|
if (fixToEmpty && q === undefined) {
|
|
80
76
|
delete input.scripts![name];
|
|
81
77
|
} else {
|
|
@@ -87,7 +83,7 @@ export const packageScript = {
|
|
|
87
83
|
}
|
|
88
84
|
|
|
89
85
|
const validOptionsString = Array.from(allowedValues.values())
|
|
90
|
-
.map(a => (a === undefined ? "(empty)" : `'${a}'`))
|
|
86
|
+
.map((a) => (a === undefined ? "(empty)" : `'${a}'`))
|
|
91
87
|
.join(", ");
|
|
92
88
|
|
|
93
89
|
context.addError({
|
|
@@ -101,3 +97,5 @@ export const packageScript = {
|
|
|
101
97
|
},
|
|
102
98
|
optionsRuntype: Options,
|
|
103
99
|
} as RuleModule<typeof Options>;
|
|
100
|
+
|
|
101
|
+
export const PackageScript = createNewRuleConversion("PackageScript", packageScript);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2019 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
|
+
import { mutateJson, PackageJson } from "@monorepolint/utils";
|
|
10
|
+
import { diff } from "jest-diff";
|
|
11
|
+
import * as r from "runtypes";
|
|
12
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
13
|
+
const Options = r.Partial({
|
|
14
|
+
dependencies: r.Dictionary(r.String),
|
|
15
|
+
devDependencies: r.Dictionary(r.String),
|
|
16
|
+
peerDependencies: r.Dictionary(r.String),
|
|
17
|
+
optionalDependencies: r.Dictionary(r.String),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type Options = r.Static<typeof Options>;
|
|
21
|
+
|
|
22
|
+
export const requireDependency = {
|
|
23
|
+
check: function expectPackageEntry(context: Context, options: Options) {
|
|
24
|
+
const packageJson = context.getPackageJson();
|
|
25
|
+
const packageJsonPath = context.getPackageJsonPath();
|
|
26
|
+
|
|
27
|
+
[
|
|
28
|
+
"dependencies" as const,
|
|
29
|
+
"devDependencies" as const,
|
|
30
|
+
"peerDependencies" as const,
|
|
31
|
+
"optionalDependencies" as const,
|
|
32
|
+
].forEach((type) => {
|
|
33
|
+
if (!options[type]) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (packageJson[type] === undefined) {
|
|
38
|
+
context.addError({
|
|
39
|
+
file: packageJsonPath,
|
|
40
|
+
message: `No ${type} block, cannot add required ${type}.`,
|
|
41
|
+
fixer: () => {
|
|
42
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
43
|
+
input[type] = options[type];
|
|
44
|
+
return input;
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
for (const [dep, version] of Object.entries(options[type]!)) {
|
|
52
|
+
if (packageJson[type][dep] !== version) {
|
|
53
|
+
context.addError({
|
|
54
|
+
file: packageJsonPath,
|
|
55
|
+
message: `Expected dependency ${dep}@${version}`,
|
|
56
|
+
longMessage: diff(`${dep}@${version}\n`, `${dep}@${packageJson[type][dep] || "missing"}\n`)!,
|
|
57
|
+
fixer: () => {
|
|
58
|
+
mutateJson<PackageJson>(packageJsonPath, context.host, (input) => {
|
|
59
|
+
input[type] = { ...input[type], [dep]: version };
|
|
60
|
+
return input;
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
optionsRuntype: Options,
|
|
69
|
+
} as RuleModule<typeof Options>;
|
|
70
|
+
|
|
71
|
+
export const RequireDependency = createNewRuleConversion("RequireDependency", requireDependency);
|
package/src/standardTsconfig.ts
CHANGED
|
@@ -5,20 +5,24 @@
|
|
|
5
5
|
*
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Context, RuleModule } from "@monorepolint/
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import minimatch from "minimatch";
|
|
8
|
+
import { Context, RuleModule } from "@monorepolint/config";
|
|
9
|
+
import { matchesAnyGlob } from "@monorepolint/utils";
|
|
10
|
+
import { diff } from "jest-diff";
|
|
11
|
+
import { createNewRuleConversion } from "./util/createNewRuleConversion.js";
|
|
13
12
|
import * as path from "path";
|
|
14
13
|
import * as r from "runtypes";
|
|
15
14
|
|
|
15
|
+
const DEFAULT_TSCONFIG_FILENAME = "tsconfig.json";
|
|
16
|
+
|
|
16
17
|
const Options = r
|
|
17
18
|
.Partial({
|
|
19
|
+
file: r.String,
|
|
18
20
|
generator: r.Function,
|
|
21
|
+
tsconfigReferenceFile: r.String,
|
|
19
22
|
template: r.Record({}).Or(r.String),
|
|
20
23
|
templateFile: r.String,
|
|
21
24
|
excludedReferences: r.Array(r.String).Or(r.Undefined),
|
|
25
|
+
additionalReferences: r.Array(r.String).Or(r.Undefined),
|
|
22
26
|
})
|
|
23
27
|
.withConstraint(({ generator, template, templateFile }) => {
|
|
24
28
|
let count = 0;
|
|
@@ -35,15 +39,18 @@ const Options = r
|
|
|
35
39
|
return count === 1 || "Expect one of { generator, template, templateFile }";
|
|
36
40
|
});
|
|
37
41
|
|
|
38
|
-
export
|
|
42
|
+
export interface Options extends r.Static<typeof Options> {}
|
|
39
43
|
|
|
40
44
|
export const standardTsconfig = {
|
|
41
|
-
check: function expectStandardTsconfig(context: Context, opts: Options) {
|
|
42
|
-
const
|
|
45
|
+
check: async function expectStandardTsconfig(context: Context, opts: Options) {
|
|
46
|
+
const tsconfigFileName = opts.file ?? DEFAULT_TSCONFIG_FILENAME;
|
|
47
|
+
const fullPath = path.resolve(context.packageDir, tsconfigFileName);
|
|
43
48
|
const generator = getGenerator(context, opts);
|
|
44
|
-
const expectedContent = generator(context);
|
|
49
|
+
const expectedContent = await generator(context);
|
|
45
50
|
|
|
46
|
-
const actualContent =
|
|
51
|
+
const actualContent = context.host.exists(fullPath)
|
|
52
|
+
? context.host.readFile(fullPath, { encoding: "utf-8" })
|
|
53
|
+
: undefined;
|
|
47
54
|
|
|
48
55
|
if (expectedContent === undefined) {
|
|
49
56
|
context.addWarning({
|
|
@@ -59,7 +66,9 @@ export const standardTsconfig = {
|
|
|
59
66
|
message: "Expect file contents to match",
|
|
60
67
|
longMessage: diff(expectedContent, actualContent, { expand: true }),
|
|
61
68
|
fixer: () => {
|
|
62
|
-
|
|
69
|
+
context.host.writeFile(fullPath, expectedContent, {
|
|
70
|
+
encoding: "utf-8",
|
|
71
|
+
});
|
|
63
72
|
},
|
|
64
73
|
});
|
|
65
74
|
}
|
|
@@ -67,43 +76,59 @@ export const standardTsconfig = {
|
|
|
67
76
|
optionsRuntype: Options,
|
|
68
77
|
} as RuleModule<typeof Options>;
|
|
69
78
|
|
|
79
|
+
export const StandardTsConfig = createNewRuleConversion("StandardTsconfig", standardTsconfig);
|
|
80
|
+
|
|
70
81
|
function getGenerator(context: Context, opts: Options) {
|
|
71
82
|
if (opts.generator) {
|
|
72
83
|
return opts.generator;
|
|
73
84
|
} else if (opts.templateFile) {
|
|
74
85
|
const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
|
|
75
86
|
const fullPath = path.resolve(workspacePackageDir, opts.templateFile);
|
|
76
|
-
const template = JSON.parse(
|
|
87
|
+
const template = JSON.parse(context.host.readFile(fullPath, { encoding: "utf-8" }));
|
|
77
88
|
|
|
78
|
-
return makeGenerator(template, opts.excludedReferences);
|
|
89
|
+
return makeGenerator(template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
|
|
79
90
|
} else if (opts.template) {
|
|
80
|
-
return makeGenerator(opts.template, opts.excludedReferences);
|
|
91
|
+
return makeGenerator(opts.template, opts.excludedReferences, opts.additionalReferences, opts.tsconfigReferenceFile);
|
|
81
92
|
} else {
|
|
82
93
|
throw new Error("Unable to make generator");
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
function makeGenerator(
|
|
87
|
-
|
|
97
|
+
function makeGenerator(
|
|
98
|
+
template: any,
|
|
99
|
+
excludedReferences: ReadonlyArray<string> | undefined,
|
|
100
|
+
additionalReferences: ReadonlyArray<string> | undefined,
|
|
101
|
+
tsconfigReferenceFile?: string
|
|
102
|
+
) {
|
|
103
|
+
return async function generator(context: Context) {
|
|
88
104
|
template = {
|
|
89
105
|
...template,
|
|
90
106
|
references: [],
|
|
91
107
|
}; // make a copy and ensure we have a references array
|
|
92
108
|
|
|
93
|
-
const nameToDirectory =
|
|
109
|
+
const nameToDirectory = await context.getWorkspaceContext().getPackageNameToDir();
|
|
94
110
|
|
|
95
111
|
const packageJson = context.getPackageJson();
|
|
96
112
|
const deps = [...Object.keys(packageJson.dependencies || {}), ...Object.keys(packageJson.devDependencies || {})];
|
|
97
113
|
|
|
98
|
-
deps
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
114
|
+
for (const dep of deps) {
|
|
115
|
+
const packageDir = nameToDirectory.get(dep);
|
|
116
|
+
if (packageDir !== undefined && (excludedReferences === undefined || matchesAnyGlob(dep, excludedReferences))) {
|
|
117
|
+
const absoluteReferencePath =
|
|
118
|
+
tsconfigReferenceFile !== undefined ? path.join(packageDir, tsconfigReferenceFile) : packageDir;
|
|
103
119
|
template.references.push({
|
|
104
|
-
path: path.relative(context.packageDir,
|
|
120
|
+
path: path.relative(context.packageDir, absoluteReferencePath),
|
|
105
121
|
});
|
|
106
|
-
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (additionalReferences) {
|
|
126
|
+
for (const additionalReference of additionalReferences) {
|
|
127
|
+
template.references.push({
|
|
128
|
+
path: additionalReference,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
107
132
|
|
|
108
133
|
return JSON.stringify(template, undefined, 2) + "\n";
|
|
109
134
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2019 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Context } from "@monorepolint/config";
|
|
9
|
+
import { diff } from "jest-diff";
|
|
10
|
+
|
|
11
|
+
export function checkAlpha(
|
|
12
|
+
context: Context,
|
|
13
|
+
block: "dependencies" | "devDependencies" | "peerDependencies" | "scripts"
|
|
14
|
+
) {
|
|
15
|
+
const packageJson = context.getPackageJson();
|
|
16
|
+
const packagePath = context.getPackageJsonPath();
|
|
17
|
+
|
|
18
|
+
const blockToSort = packageJson[block];
|
|
19
|
+
|
|
20
|
+
if (blockToSort === undefined) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const actualOrder = Object.keys(blockToSort);
|
|
25
|
+
const expectedOrder = actualOrder.slice().sort(); // sort mutates, so we need to copy the previous result
|
|
26
|
+
|
|
27
|
+
if (!arrayOrderCompare(actualOrder, expectedOrder)) {
|
|
28
|
+
context.addError({
|
|
29
|
+
file: packagePath,
|
|
30
|
+
message: createIncorrectOrderErrorMessage(block, packageJson.name!),
|
|
31
|
+
longMessage: diff(expectedOrder, actualOrder, { expand: true }),
|
|
32
|
+
fixer: () => {
|
|
33
|
+
const expectedDependencies: Record<string, string> = {};
|
|
34
|
+
|
|
35
|
+
expectedOrder.forEach((dep) => {
|
|
36
|
+
expectedDependencies[dep] = blockToSort[dep];
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const newPackageJson = { ...packageJson };
|
|
40
|
+
newPackageJson[block] = expectedDependencies;
|
|
41
|
+
context.host.writeJson(packagePath, newPackageJson);
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function arrayOrderCompare(a: ReadonlyArray<string>, b: ReadonlyArray<string>) {
|
|
48
|
+
for (let index = 0; index < a.length; index++) {
|
|
49
|
+
if (a[index] !== b[index]) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createIncorrectOrderErrorMessage(block: string, packageName: string) {
|
|
58
|
+
return `Incorrect order of ${block} in ${packageName}'s package.json`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2022 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Checker, Context, NewRuleModule, RuleModule, RuleEntry } from "@monorepolint/config";
|
|
9
|
+
import * as r from "runtypes";
|
|
10
|
+
|
|
11
|
+
// tslint:disable max-classes-per-file
|
|
12
|
+
|
|
13
|
+
let id = 0;
|
|
14
|
+
export class NewRuleConverterBase<T extends r.Runtype<unknown>> implements NewRuleModule<T> {
|
|
15
|
+
public readonly id: string;
|
|
16
|
+
options: r.Static<T> | undefined;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
public readonly name: string,
|
|
20
|
+
public checkFunc: Checker<T>,
|
|
21
|
+
public readonly optionsRuntype: T,
|
|
22
|
+
public readonly ruleEntry: RuleEntry<r.Static<T>>
|
|
23
|
+
) {
|
|
24
|
+
this.options = ruleEntry.options;
|
|
25
|
+
this.id = `${this.name} :: ${id++}`;
|
|
26
|
+
//
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public check = (context: Context) => this.checkFunc(context, this.ruleEntry.options, { id: this.id });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function createNewRuleConversion<T extends r.Runtype<unknown>>(name: string, old: RuleModule<T>) {
|
|
33
|
+
return class NewRule extends NewRuleConverterBase<T> {
|
|
34
|
+
constructor(ruleEntry: RuleEntry<r.Static<T>>) {
|
|
35
|
+
super(name, old.check, old.optionsRuntype, ruleEntry);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright 2019 Palantir Technologies, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the MIT license. See LICENSE file in the project root for details.
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { existsSync, mkdirSync } from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
|
|
11
|
+
export function makeDirectoryRecursively(directoryPath: string) {
|
|
12
|
+
// node < 10 doesn't support mkdirSync w/ recursive: true
|
|
13
|
+
// so we manually do it instead
|
|
14
|
+
const dirSegments = directoryPath.split(path.sep);
|
|
15
|
+
for (let i = 0; i < dirSegments.length; i++) {
|
|
16
|
+
if (dirSegments[i].length > 0) {
|
|
17
|
+
// we skip the empty segment
|
|
18
|
+
const curDirPath = dirSegments.slice(0, i + 1).join(path.sep);
|
|
19
|
+
if (!existsSync(curDirPath)) {
|
|
20
|
+
mkdirSync(curDirPath);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|