Skip to content

Commit 9457a21

Browse files
committed
feat(listable): Output JSON adjacency list with --graph
Credit: @yacineb Original PR: #1970
1 parent d410a58 commit 9457a21

File tree

6 files changed

+104
-0
lines changed

6 files changed

+104
-0
lines changed

commands/changed/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ package-2
2727
- [`-l`, `--long`](https://github.com/lerna/lerna/tree/master/commands/list#--long)
2828
- [`-p`, `--parseable`](https://github.com/lerna/lerna/tree/master/commands/list#--parseable)
2929
- [`--toposort`](https://github.com/lerna/lerna/tree/master/commands/list#--toposort)
30+
- [`--graph`](https://github.com/lerna/lerna/tree/master/commands/list#--graph)
3031

3132
Unlike `lerna ls`, however, `lerna changed` **does not** support [filter options](https://www.npmjs.com/package/@lerna/filter-options), as filtering is not supported by `lerna version` or `lerna publish`.
3233

commands/list/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ In any case, you can always pass `--loglevel silent` to create pristine chains o
3232
- [`-l`, `--long`](#--long)
3333
- [`-p`, `--parseable`](#--parseable)
3434
- [`--toposort`](#--toposort)
35+
- [`--graph`](#--graph)
3536

3637
`lerna ls` also respects all available [Filter Flags](https://www.npmjs.com/package/@lerna/filter-options).
3738

@@ -143,3 +144,30 @@ $ lerna ls --toposort
143144
package-2
144145
package-1
145146
```
147+
148+
### `--graph`
149+
150+
Show dependency graph as a JSON-formatted [adjacency list](https://en.wikipedia.org/wiki/Adjacency_list).
151+
152+
```sh
153+
$ lerna ls --graph
154+
{
155+
"pkg-1": [
156+
"pkg-2"
157+
],
158+
"pkg-2": []
159+
}
160+
161+
$ lerna ls --graph --all
162+
{
163+
"pkg-1": [
164+
"pkg-2"
165+
],
166+
"pkg-2": [
167+
"pkg-3"
168+
],
169+
"pkg-3": [
170+
"pkg-2"
171+
]
172+
}
173+
```

utils/listable/__tests__/listable-format.test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,37 @@ pkg-3 v3.0.0 pkgs/pkg-3 (PRIVATE)
166166
`);
167167
});
168168

169+
test("graph output", () => {
170+
const { text } = formatWithOptions({ graph: true });
171+
172+
expect(text).toMatchInlineSnapshot(`
173+
{
174+
"pkg-1": [
175+
"pkg-2"
176+
],
177+
"pkg-2": []
178+
}
179+
`);
180+
});
181+
182+
test("all graph output", () => {
183+
const { text } = formatWithOptions({ graph: true, all: true });
184+
185+
expect(text).toMatchInlineSnapshot(`
186+
{
187+
"pkg-1": [
188+
"pkg-2"
189+
],
190+
"pkg-2": [
191+
"pkg-3"
192+
],
193+
"pkg-3": [
194+
"pkg-2"
195+
]
196+
}
197+
`);
198+
});
199+
169200
test("parseable output", () => {
170201
const { text } = formatWithOptions({ parseable: true });
171202

utils/listable/__tests__/listable-options.test.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,8 @@ describe("listable.options()", () => {
4141
it("provides --toposort", () => {
4242
expect(parsed("--toposort")).toHaveProperty("toposort", true);
4343
});
44+
45+
it("provides --graph", () => {
46+
expect(parsed("--graph")).toHaveProperty("graph", true);
47+
});
4448
});

utils/listable/lib/listable-format.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ function listableFormat(pkgList, options) {
2020
text = formatNDJSON(resultList);
2121
} else if (viewOptions.showParseable) {
2222
text = formatParseable(resultList, viewOptions);
23+
} else if (viewOptions.showGraph) {
24+
text = formatJSONGraph(resultList, viewOptions);
2325
} else {
2426
text = formatColumns(resultList, viewOptions);
2527
}
@@ -37,6 +39,7 @@ function parseViewOptions(options) {
3739
showNDJSON: options.ndjson,
3840
showParseable: options.parseable,
3941
isTopological: options.toposort,
42+
showGraph: options.graph,
4043
};
4144
}
4245

@@ -71,6 +74,38 @@ function formatNDJSON(resultList) {
7174
.join("\n");
7275
}
7376

77+
function formatJSONGraph(resultList, viewOptions) {
78+
// https://en.wikipedia.org/wiki/Adjacency_list
79+
const graph = {};
80+
const getNeighbors = viewOptions.showAll
81+
? pkg =>
82+
Object.keys(
83+
Object.assign(
84+
{},
85+
pkg.devDependencies,
86+
pkg.peerDependencies,
87+
pkg.optionalDependencies,
88+
pkg.dependencies
89+
)
90+
).sort()
91+
: pkg =>
92+
Object.keys(
93+
Object.assign(
94+
{},
95+
// no devDependencies
96+
// no peerDependencies
97+
pkg.optionalDependencies,
98+
pkg.dependencies
99+
)
100+
).sort();
101+
102+
for (const pkg of resultList) {
103+
graph[pkg.name] = getNeighbors(pkg);
104+
}
105+
106+
return JSON.stringify(graph, null, 2);
107+
}
108+
74109
function makeParseable(pkg) {
75110
const result = [pkg.location, pkg.name];
76111

utils/listable/lib/listable-options.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,10 @@ function listableOptions(yargs) {
3737
describe: "Sort packages in topological order instead of lexical by directory",
3838
type: "boolean",
3939
},
40+
graph: {
41+
group: "Command Options:",
42+
describe: "Show dependency graph as a JSON-formatted adjacency list",
43+
type: "boolean",
44+
},
4045
});
4146
}

0 commit comments

Comments
 (0)