-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- parse package.json - fetch peer dependencies online - check if there are mismatches in peers - keep things testable via functional
- Loading branch information
Showing
15 changed files
with
462 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { | ||
blue, | ||
cyan, | ||
gray, | ||
yellow, | ||
} from "https://deno.land/[email protected]/fmt/colors.ts"; | ||
|
||
export const colour = { | ||
dependency: blue, | ||
file: cyan, | ||
subdued: gray, | ||
version: yellow, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export { literal, object, record, string } from "https://esm.sh/[email protected]"; | ||
export { coerce, satisfies, SemVer, Range } from "https://esm.sh/[email protected]"; | ||
|
||
export { | ||
assertEquals, | ||
assertThrows, | ||
} from "https://deno.land/[email protected]/testing/asserts.ts"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { assertEquals } from "./deps.ts"; | ||
import { Range, SemVer } from "./deps.ts"; | ||
import { fetch_peer_dependencies } from "./fetch_peer_dependencies.ts"; | ||
|
||
Deno.test("Can get peer dependencies", async () => { | ||
const with_peer_deps = await fetch_peer_dependencies([ | ||
// { name: "@guardian/source-foundations", version: new SemVer("8.0.0") }, | ||
{ | ||
name: "@guardian/core-web-vitals", | ||
version: new SemVer("2.0.2"), | ||
peers: [], | ||
}, | ||
// { name: "@guardian/libs", version: new SemVer("12.0.0") }, | ||
// { name: "@guardian/ab-react", version: new SemVer("2.0.1") }, | ||
]); | ||
|
||
assertEquals(with_peer_deps, [ | ||
{ | ||
name: "@guardian/core-web-vitals", | ||
version: new SemVer("2.0.2"), | ||
peers: [ | ||
{ | ||
name: "@guardian/libs", | ||
range: new Range("^12.0.0"), | ||
optional: false, | ||
}, | ||
{ | ||
name: "tslib", | ||
range: new Range("^2.4.1"), | ||
optional: false, | ||
}, | ||
{ | ||
name: "typescript", | ||
range: new Range("^4.3.2"), | ||
optional: true, | ||
}, | ||
{ | ||
name: "web-vitals", | ||
range: new Range("^2.0.0"), | ||
optional: false, | ||
}, | ||
], | ||
}, | ||
]); | ||
}); | ||
|
||
Deno.test("Can get optional peer dependencies", async () => { | ||
const peer_deps = await fetch_peer_dependencies([ | ||
{ name: "@guardian/libs", version: new SemVer("12.0.0"), peers: [] }, | ||
]); | ||
|
||
assertEquals(peer_deps, [ | ||
{ | ||
name: "@guardian/libs", | ||
version: new SemVer("12.0.0"), | ||
peers: [ | ||
{ | ||
name: "tslib", | ||
range: new Range("^2.4.1"), | ||
optional: false, | ||
}, | ||
{ | ||
name: "typescript", | ||
range: new Range("^4.3.2"), | ||
optional: true, | ||
}, | ||
], | ||
}, | ||
]); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { literal, object, Range, record, string } from "./deps.ts"; | ||
import { Dependency, PeerDependency } from "./types.ts"; | ||
|
||
const { parseAsync: parse_peers } = object({ | ||
peerDependencies: record(string()).optional(), | ||
peerDependenciesMeta: record(object({ optional: literal(true) })).optional(), | ||
}); | ||
|
||
export const fetch_peer_dependencies = ( | ||
dependencies: Dependency[], | ||
): Promise<Dependency[]> => | ||
Promise.all( | ||
dependencies.map((dependency) => | ||
fetch( | ||
new URL( | ||
`${dependency.name}@${dependency.version.version}/package.json`, | ||
"https://esm.sh/", | ||
), | ||
) | ||
.then((res) => res.json()) | ||
.then(parse_peers) | ||
.then(({ peerDependencies = {}, peerDependenciesMeta }) => ({ | ||
...dependency, | ||
peers: Object.entries(peerDependencies).map(([name, range]) => ({ | ||
name, | ||
range: new Range(range), | ||
optional: !!peerDependenciesMeta?.[name]?.optional, | ||
})), | ||
})) | ||
.catch((error) => { | ||
console.error("🚨 Failed to parse package.json for", dependency.name); | ||
throw error; | ||
}) | ||
), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { assertEquals } from "./deps.ts"; | ||
import { SemVer, Range } from "./deps.ts"; | ||
import { find_mismatched_peer_dependencies } from "./find_mismatches.ts"; | ||
|
||
Deno.test("Works when all depencies are matches", () => { | ||
assertEquals( | ||
find_mismatched_peer_dependencies([ | ||
{ | ||
name: "one", | ||
version: new SemVer("1.0.0"), | ||
peers: [ | ||
{ | ||
name: "two", | ||
optional: false, | ||
range: new Range("^2.0.0"), | ||
}, | ||
], | ||
}, | ||
{ name: "two", version: new SemVer("2.0.2"), peers: [] }, | ||
]), | ||
[] | ||
); | ||
}); | ||
|
||
Deno.test("Fails on invalid range", () => { | ||
assertEquals( | ||
find_mismatched_peer_dependencies([ | ||
{ | ||
name: "one", | ||
version: new SemVer("1.0.0"), | ||
peers: [ | ||
{ | ||
name: "two", | ||
optional: false, | ||
range: new Range("^2.0.3"), | ||
}, | ||
], | ||
}, | ||
{ name: "two", version: new SemVer("2.0.2"), peers: [] }, | ||
]), | ||
[ | ||
{ | ||
name: "two", | ||
optional: false, | ||
range: new Range("^2.0.3"), | ||
required_by: "one", | ||
}, | ||
] | ||
); | ||
}); | ||
|
||
Deno.test("Allows optional deps to fail if absent", () => { | ||
assertEquals( | ||
find_mismatched_peer_dependencies([ | ||
{ | ||
name: "one", | ||
version: new SemVer("1.0.0"), | ||
peers: [ | ||
{ | ||
name: "two", | ||
optional: true, | ||
range: new Range("^2.0.3"), | ||
}, | ||
], | ||
}, | ||
]), | ||
[] | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { colour } from "./colours.ts"; | ||
import { satisfies } from "./deps.ts"; | ||
import { Dependency } from "./types.ts"; | ||
|
||
export const find_mismatched_peer_dependencies = ( | ||
dependencies: Dependency[], | ||
) => { | ||
const peers = dependencies.flatMap(({ name, peers }) => | ||
peers.map((peer) => ({ ...peer, required_by: name })) | ||
); | ||
|
||
const mismatched = peers.filter((peer_dependency) => { | ||
const local_version = dependencies.find( | ||
({ name }) => name === peer_dependency.name, | ||
); | ||
if (!local_version) { | ||
return !peer_dependency.optional; | ||
} | ||
return !satisfies(local_version.version, peer_dependency.range); | ||
}); | ||
|
||
if (mismatched.length === 0) { | ||
console.info(`✅ All ${colour.file("peerDependencies")} satisfied}`); | ||
} else { | ||
console.error( | ||
`🚨 The following ${colour.file("peerDependencies")} are unsatisfied:`, | ||
); | ||
|
||
for (const { name, range, required_by } of mismatched) { | ||
console.error( | ||
` - ${ | ||
[ | ||
colour.dependency(name), | ||
colour.subdued("@"), | ||
colour.version(range.raw), | ||
" (from ", | ||
colour.dependency(required_by), | ||
" )", | ||
].join("") | ||
}`, | ||
); | ||
} | ||
} | ||
|
||
return mismatched; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"dependencies": { | ||
"@guardian/source-foundations": "8.0.0", | ||
"@guardian/core-web-vitals": "2.0.2" | ||
}, | ||
"devDependencies": { | ||
"@guardian/libs": "^12", | ||
"@guardian/ab-react": "^2.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"dependencies": { | ||
"@guardian/source-foundations": "8.0.0", | ||
"@guardian/libs": "^12" | ||
}, | ||
"devDependencies": { | ||
"@guardian/libs": "^12" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"dependencies": { | ||
"@guardian/source-foundations": "8.0.0" | ||
}, | ||
"devDependencies": { | ||
"typescript": "^4.2.4", | ||
"@guardian/libs": "^12", | ||
"@guardian/ab-react": "^2.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"dependencies": { | ||
"@guardian/ab-core": "2.0.0", | ||
"@guardian/core-web-vitals": "2.0.2", | ||
"@guardian/source-foundations": "8.0.0", | ||
"react": "^16.13.1", | ||
"react-dom": "^16.13.1", | ||
"tslib": "^2.4.1", | ||
"web-vitals": "^2.0.1" | ||
}, | ||
"devDependencies": { | ||
"@guardian/libs": "^12", | ||
"@guardian/ab-react": "^2.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Deno.test("Parses package.json", () => { | ||
return; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { literal, object, record, string } from "./deps.ts"; | ||
import { coerce, satisfies, SemVer } from "./deps.ts"; | ||
import { | ||
blue, | ||
cyan, | ||
gray, | ||
yellow, | ||
} from "https://deno.land/[email protected]/fmt/colors.ts"; | ||
import { parse_declared_dependencies } from "./parse_dependencies.ts"; | ||
import { fetch_peer_dependencies } from "./fetch_peer_dependencies.ts"; | ||
import { colour } from "./colours.ts"; | ||
import { Dependency, PeerDependency } from "./types.ts"; | ||
import { find_mismatched_peer_dependencies } from "./find_mismatches.ts"; | ||
|
||
// https://unpkg.com/ | ||
|
||
const [package_file] = Deno.args; | ||
|
||
if (!package_file) { | ||
console.error("🚨 No package.json passed as argument"); | ||
Deno.exit(1); | ||
} | ||
|
||
const filename = Deno.cwd() + "/" + package_file; | ||
|
||
const package_content = await Deno.readTextFile(filename).catch(() => ""); | ||
|
||
if (package_content) { | ||
console.info(`✅ Found package.json file`); | ||
} else { | ||
console.error("🚨 No package.json found at", cyan(filename)); | ||
Deno.exit(1); | ||
} | ||
|
||
const dependencies = parse_declared_dependencies(package_content); | ||
|
||
if (dependencies.length === 0) { | ||
console.info("✅ You have no dependencies and therefore no issues!"); | ||
Deno.exit(); | ||
} | ||
|
||
const dependencies_with_peers = await fetch_peer_dependencies(dependencies); | ||
|
||
const { length: number_of_mismatched_deps } = find_mismatched_peer_dependencies( | ||
dependencies_with_peers, | ||
); | ||
|
||
if (number_of_mismatched_deps === 0) { | ||
console.info("✅ Everything is fine with your dependencies"); | ||
} else { | ||
console.info("🚨 This shal"); | ||
} | ||
|
||
Deno.exit(number_of_mismatched_deps); |
Oops, something went wrong.