Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow dependecies to use the workspace: protocol and add "workspaceProtocol": "require" config option #204

Merged
merged 3 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@0.2.1/schema.json",
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "Thinkmill/manypkg" }
],
"commit": false,
"linked": [],
"access": "public"
"access": "public",
"baseBranch": "main"
}
5 changes: 5 additions & 0 deletions .changeset/forty-needles-doubt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@manypkg/cli": patch
---

Allow dependecies to use the `workspace:` protocol and support adding `"workspaceProtocol": "require"` to the `manypkg` config to require it.
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,7 @@ So that only a single version of an external package will be installed because h

### How it's fixed

The most commonly used range of the dependency is set as the range at every non-peer dependency place it is depended on.
If for some reason, every range is used the same amount of times, they'll all be fixed to the highest version.
The most commonly used range of the dependency is set as the range at every non-peer dependency place it is depended on. If for some reason, every range is used the same amount of times, they'll all be fixed to the highest version.

### Examples

Expand Down Expand Up @@ -287,6 +286,18 @@ Having a `repository` field is helpful so there is a link to the source of a pac

This is fixed by setting the correct URL.

## `workspace:` protocol required

If `"workspaceProtocol": "require"` is set in the `manypkg` config in the root `package.json`, all dependencies on internal packages are required to use the `workspace:` protocol.

### Why it's a rule

If you want to enforce the usage of the `workspace:` protocol.

#### How it's fixed

Dependencies are changed to `workspace:^`. Anything else is also allowed after the `workspace:` though.

## License

Copyright (c) 2023 Thinkmill Labs Pty Ltd. Licensed under the MIT License.
3 changes: 2 additions & 1 deletion packages/cli/src/checks/INTERNAL_MISMATCH.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ export default makeCheck<ErrorType>({
for (let depName in deps) {
let range = deps[depName];
let dependencyWorkspace = allWorkspaces.get(depName);

if (
dependencyWorkspace !== undefined &&
!range.startsWith("npm:") &&
!range.startsWith("workspace:") &&
!semver.satisfies(dependencyWorkspace.packageJson.version, range)
) {
errors.push({
Expand Down
46 changes: 46 additions & 0 deletions packages/cli/src/checks/WORKSPACE_REQUIRED.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { makeCheck, NORMAL_DEPENDENCY_TYPES } from "./utils";
import { Package } from "@manypkg/get-packages";

export type ErrorType = {
type: "WORKSPACE_REQUIRED";
workspace: Package;
depType: typeof NORMAL_DEPENDENCY_TYPES[number];
depName: string;
};

export default makeCheck<ErrorType>({
validate: (workspace, allWorkspaces, root, opts) => {
if (opts.workspaceProtocol !== "require") return [];
let errors: ErrorType[] = [];
for (let depType of NORMAL_DEPENDENCY_TYPES) {
let deps = workspace.packageJson[depType];
if (deps) {
for (let depName in deps) {
if (
allWorkspaces.has(depName) &&
!deps[depName].startsWith("workspace:")
) {
errors.push({
type: "WORKSPACE_REQUIRED",
workspace,
depName,
depType,
});
}
}
}
}

return errors;
},
fix: (error) => {
let deps = error.workspace.packageJson[error.depType];
if (deps && deps[error.depName]) {
deps[error.depName] = "workspace:^";
}
return { requiresInstall: true };
},
print: (error) =>
`${error.workspace.packageJson.name} has a dependency on ${error.depName} without using the workspace: protocol but this project requires using the workspace: protocol, please change it to workspace:^ or etc.`,
type: "all",
});
11 changes: 10 additions & 1 deletion packages/cli/src/checks/__tests__/INTERNAL_MISMATCH.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ describe("internal mismatch", () => {
let errors = makeCheck.validate(dependsOnOne, ws, rootWorkspace, {});
expect(errors.length).toEqual(0);
});
it("should allow workspace: protocol", () => {
let ws = getWS();
let dependsOnOne = getFakeWS("depends-on-one");
dependsOnOne.packageJson.dependencies = {
"pkg-1": "workspace:^",
};
ws.set("depends-on-one", dependsOnOne);
let errors = makeCheck.validate(dependsOnOne, ws, rootWorkspace, {});
expect(errors.length).toEqual(0);
});
it("should error if internal version is not compatible", () => {
let ws = getWS();
let dependsOnOne = getFakeWS("depends-on-one");
Expand Down Expand Up @@ -100,5 +110,4 @@ describe("internal mismatch", () => {
expect(errors.length).toEqual(0);
}
);

});
54 changes: 54 additions & 0 deletions packages/cli/src/checks/__tests__/WORKSPACE_REQUIRED.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { getWS, getFakeWS, getRootWS } from "../../test-helpers";
import makeCheck from "../WORKSPACE_REQUIRED";
let rootWorkspace = getRootWS();

test("should not error if not using workspaceProtocol: require", () => {
let ws = getWS();
let dependsOnOne = getFakeWS("depends-on-one");
dependsOnOne.packageJson.dependencies = {
"pkg-1": "^1.0.0",
};
ws.set("depends-on-one", dependsOnOne);
let errors = makeCheck.validate(dependsOnOne, ws, rootWorkspace, {});
expect(errors.length).toEqual(0);
});

test("should error if using workspaceProtocol: require", () => {
let ws = getWS();
let dependsOnOne = getFakeWS("depends-on-one");
dependsOnOne.packageJson.dependencies = {
"pkg-1": "^1.0.0",
};
ws.set("depends-on-one", dependsOnOne);
let errors = makeCheck.validate(dependsOnOne, ws, rootWorkspace, {
workspaceProtocol: "require",
});
expect(errors).toEqual([
{
type: "WORKSPACE_REQUIRED",
workspace: dependsOnOne,
depName: "pkg-1",
depType: "dependencies",
},
]);
});

test("should fix if using workspaceProtocol: require", () => {
let ws = getWS();
let dependsOnOne = getFakeWS("depends-on-one");
dependsOnOne.packageJson.dependencies = {
"pkg-1": "^1.0.0",
};
ws.set("depends-on-one", dependsOnOne);
const errors = makeCheck.validate(dependsOnOne, ws, rootWorkspace, {
workspaceProtocol: "require",
});
expect(errors).toHaveLength(1);
const result = makeCheck.fix(errors[0], {
workspaceProtocol: "require",
});
expect(dependsOnOne.packageJson.dependencies).toEqual({
"pkg-1": "workspace:^",
});
expect(result).toEqual({ requiresInstall: true });
});
2 changes: 2 additions & 0 deletions packages/cli/src/checks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import MULTIPLE_DEPENDENCY_TYPES from "./MULTIPLE_DEPENDENCY_TYPES";
import ROOT_HAS_DEV_DEPENDENCIES from "./ROOT_HAS_DEV_DEPENDENCIES";
import UNSORTED_DEPENDENCIES from "./UNSORTED_DEPENDENCIES";
import INCORRECT_REPOSITORY_FIELD from "./INCORRECT_REPOSITORY_FIELD";
import WORKSPACE_REQUIRED from "./WORKSPACE_REQUIRED";

export let checks = {
EXTERNAL_MISMATCH,
Expand All @@ -16,4 +17,5 @@ export let checks = {
ROOT_HAS_DEV_DEPENDENCIES,
UNSORTED_DEPENDENCIES,
INCORRECT_REPOSITORY_FIELD,
WORKSPACE_REQUIRED,
};
6 changes: 5 additions & 1 deletion packages/cli/src/checks/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ export const DEPENDENCY_TYPES = [
"peerDependencies",
] as const;

export type Options = { defaultBranch?: string; ignoredRules?: string[] };
export type Options = {
defaultBranch?: string;
ignoredRules?: string[];
workspaceProtocol?: "allow" | "require";
};

type RootCheck<ErrorType> = {
type: "root";
Expand Down
Loading