|
|
@@ -3,9 +3,6 @@ import path from "path";
|
|
|
|
|
|
import { hideBin } from "yargs/helpers";
|
|
|
|
|
|
-type Format = "tree" | "csv";
|
|
|
-const formats: ReadonlyArray<Format> = ["tree", "csv"];
|
|
|
-
|
|
|
const args = yargs(hideBin(process.argv))
|
|
|
.option("package", {
|
|
|
type: "string",
|
|
|
@@ -13,10 +10,15 @@ const args = yargs(hideBin(process.argv))
|
|
|
require: true
|
|
|
})
|
|
|
.option("format", {
|
|
|
- choices: formats,
|
|
|
+ choices: ["tree", "csv"],
|
|
|
demandOption: true,
|
|
|
default: "tree"
|
|
|
})
|
|
|
+ .option("filter", {
|
|
|
+ choices: ["none", "oracle"],
|
|
|
+ demandOption: true,
|
|
|
+ default: "none"
|
|
|
+ })
|
|
|
.help()
|
|
|
.argv;
|
|
|
|
|
|
@@ -32,6 +34,7 @@ interface Package {
|
|
|
|
|
|
type PackageLockDependencies = Dictionary<{
|
|
|
version: string;
|
|
|
+ dev: boolean;
|
|
|
requires?: Dictionary<string>;
|
|
|
dependencies?: PackageLockDependencies;
|
|
|
}>
|
|
|
@@ -55,13 +58,13 @@ type Leaf<T> = {
|
|
|
value: T;
|
|
|
}
|
|
|
|
|
|
-type PackageLockTree = Tree<{ name: string, version: string }>;
|
|
|
+type PackageLockTree = Tree<{ name: string, version: string, dev: boolean }>;
|
|
|
|
|
|
|
|
|
|
|
|
const constructDepTree = (packageName: string, context: PackageLockDependencies, stack: string[] = []): PackageLockTree => {
|
|
|
const dependency = context[packageName];
|
|
|
- const value = { name: packageName, version: dependency.version };
|
|
|
+ const value = { name: packageName, version: dependency.version, dev: dependency.dev };
|
|
|
if (!dependency.requires) {
|
|
|
return { type: "leaf", value };
|
|
|
}
|
|
|
@@ -73,21 +76,19 @@ const constructDepTree = (packageName: string, context: PackageLockDependencies,
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-const displayDepTree = (tree: PackageLockTree, level = 1): void => {
|
|
|
- console.log(`${" ".repeat(level - 1)}${tree.value.name}@${tree.value.version}`);
|
|
|
- if (tree.type === "node") {
|
|
|
- tree.children.forEach(t => displayDepTree(t, level + 1));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-const displayDepTreeAsCsv = (tree: PackageLockTree, depType: "dependency" | "devDependency", stack: string[] = []): void => {
|
|
|
- console.log(`${tree.value.name},${tree.value.version},${stack[0] ?? ""},${stack[stack.length - 1] ?? ""},${depType}`);
|
|
|
- if (tree.type === "node") {
|
|
|
- tree.children.forEach(t => displayDepTreeAsCsv(t, depType, [...stack, `${tree.value.name}@${tree.value.version}`]))
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
+const displayDepTree = (format: (node: PackageLockTree, parents: string[]) => string) =>
|
|
|
+ (filter: (node: PackageLockTree, parents: string[]) => boolean) =>
|
|
|
+ (tree: PackageLockTree) => {
|
|
|
+ const iter = (tree: PackageLockTree, stack: string[] = []) => {
|
|
|
+ if (filter(tree, stack)) {
|
|
|
+ console.log(format(tree, stack));
|
|
|
+ }
|
|
|
+ if (tree.type === "node") {
|
|
|
+ tree.children.forEach(t => iter(t, [...stack, `${tree.value.name}@${tree.value.version}`]))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ iter(tree);
|
|
|
+ }
|
|
|
|
|
|
|
|
|
Promise.all<Package, PackageLock>([
|
|
|
@@ -96,24 +97,19 @@ Promise.all<Package, PackageLock>([
|
|
|
])
|
|
|
.then(([json, jsonLock]) => {
|
|
|
const dependencyTree = Object.keys(json.dependencies)
|
|
|
+ .concat(Object.keys(json.devDependencies ?? {}))
|
|
|
.map(depName => constructDepTree(depName, jsonLock.dependencies));
|
|
|
- if (args.format === "tree") {
|
|
|
- console.log("--------------------- dependencies --------------------");
|
|
|
- dependencyTree.forEach(t => displayDepTree(t));
|
|
|
- }
|
|
|
if (args.format === "csv") {
|
|
|
console.log("name,version,root,parent,type");
|
|
|
- dependencyTree.forEach(t => displayDepTreeAsCsv(t, "dependency"));
|
|
|
- }
|
|
|
- const devDependencyTree = Object.keys(json.devDependencies ?? {})
|
|
|
- .map(devDepName => constructDepTree(devDepName, jsonLock.dependencies));
|
|
|
- if (args.format === "tree") {
|
|
|
- console.log("-------------------- devDependencies --------------------");
|
|
|
- devDependencyTree.forEach(t => displayDepTree(t));
|
|
|
- }
|
|
|
- if (args.format === "csv") {
|
|
|
- devDependencyTree.forEach(t => displayDepTreeAsCsv(t, "devDependency"));
|
|
|
}
|
|
|
+ const format = args.format === "tree"
|
|
|
+ ? (node: PackageLockTree, parents: string[]) => `${" ".repeat(parents.length)}${node.value.name}@${node.value.version}${node.value.dev ? " (dev)" : ""}`
|
|
|
+ : (node: PackageLockTree, parents: string[]) => `${node.value.name},${node.value.version},${parents[0] ?? ""},${parents[parents.length - 1] ?? ""},${node.value.dev ? "devDependency" : "dependency"}`;
|
|
|
+ const filter = args.filter === "oracle"
|
|
|
+ ? (node: PackageLockTree, parents: string[]) => (parents.length === 0 && !node.value.name.startsWith("@os")) || (!node.value.name.startsWith("@o") && parents.length > 1 && parents.every(p => p.startsWith("@os")))
|
|
|
+ : (node: PackageLockTree, parents: string[]) => true;
|
|
|
+ const display = displayDepTree(format)(filter);
|
|
|
+ dependencyTree.forEach(t => display(t));
|
|
|
})
|
|
|
.catch(reson => {
|
|
|
console.error(reson);
|