workspace-tools 0.20.0 → 0.21.0

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/CHANGELOG.json CHANGED
@@ -2,7 +2,22 @@
2
2
  "name": "workspace-tools",
3
3
  "entries": [
4
4
  {
5
- "date": "Thu, 23 Jun 2022 20:24:10 GMT",
5
+ "date": "Fri, 01 Jul 2022 14:55:58 GMT",
6
+ "tag": "workspace-tools_v0.21.0",
7
+ "version": "0.21.0",
8
+ "comments": {
9
+ "minor": [
10
+ {
11
+ "author": "ken@gizzar.com",
12
+ "package": "workspace-tools",
13
+ "comment": "adds a package graph implementation",
14
+ "commit": "28ba85b087e3e3bb8715ea637563793fbb97b069"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Thu, 23 Jun 2022 20:24:15 GMT",
6
21
  "tag": "workspace-tools_v0.20.0",
7
22
  "version": "0.20.0",
8
23
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # Change Log - workspace-tools
2
2
 
3
- This log was last generated on Thu, 23 Jun 2022 20:24:10 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 01 Jul 2022 14:55:58 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 0.21.0
8
+
9
+ Fri, 01 Jul 2022 14:55:58 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - adds a package graph implementation (ken@gizzar.com)
14
+
7
15
  ## 0.20.0
8
16
 
9
- Thu, 23 Jun 2022 20:24:10 GMT
17
+ Thu, 23 Jun 2022 20:24:15 GMT
10
18
 
11
19
  ### Minor changes
12
20
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const graph_1 = require("../graph");
4
+ describe("createPackageGraph", () => {
5
+ it("can get linear dependencies", () => {
6
+ const allPackages = {
7
+ a: stubPackage("a", ["b"]),
8
+ b: stubPackage("b", ["c"]),
9
+ c: stubPackage("c"),
10
+ };
11
+ const actual = (0, graph_1.createPackageGraph)(allPackages, { namePatterns: ["a"], includeDependencies: true });
12
+ expect(actual).toMatchInlineSnapshot(`
13
+ Object {
14
+ "dependencies": Array [
15
+ Object {
16
+ "dependency": "b",
17
+ "name": "a",
18
+ },
19
+ Object {
20
+ "dependency": "c",
21
+ "name": "b",
22
+ },
23
+ ],
24
+ "packages": Array [
25
+ "a",
26
+ "b",
27
+ "c",
28
+ ],
29
+ }
30
+ `);
31
+ });
32
+ it("can represent a graph with some nodes with no edges", () => {
33
+ const allPackages = {
34
+ a: stubPackage("a"),
35
+ b: stubPackage("b"),
36
+ c: stubPackage("c"),
37
+ };
38
+ const actual = (0, graph_1.createPackageGraph)(allPackages);
39
+ expect(actual).toMatchInlineSnapshot(`
40
+ Object {
41
+ "dependencies": Array [],
42
+ "packages": Array [
43
+ "c",
44
+ "b",
45
+ "a",
46
+ ],
47
+ }
48
+ `);
49
+ });
50
+ it("can get linear dependents", () => {
51
+ const allPackages = {
52
+ a: stubPackage("a", ["b"]),
53
+ b: stubPackage("b", ["c"]),
54
+ c: stubPackage("c"),
55
+ };
56
+ const actual = (0, graph_1.createPackageGraph)(allPackages, { namePatterns: ["c"], includeDependents: true });
57
+ expect(actual).toMatchInlineSnapshot(`
58
+ Object {
59
+ "dependencies": Array [
60
+ Object {
61
+ "dependency": "c",
62
+ "name": "b",
63
+ },
64
+ Object {
65
+ "dependency": "b",
66
+ "name": "a",
67
+ },
68
+ ],
69
+ "packages": Array [
70
+ "c",
71
+ "b",
72
+ "a",
73
+ ],
74
+ }
75
+ `);
76
+ });
77
+ it("will handle circular dependencies", () => {
78
+ const allPackages = {
79
+ a: stubPackage("a", ["b"]),
80
+ b: stubPackage("b", ["c"]),
81
+ c: stubPackage("c", ["a"]),
82
+ };
83
+ const actual = (0, graph_1.createPackageGraph)(allPackages, { namePatterns: ["a"], includeDependencies: true });
84
+ expect(actual).toMatchInlineSnapshot(`
85
+ Object {
86
+ "dependencies": Array [
87
+ Object {
88
+ "dependency": "b",
89
+ "name": "a",
90
+ },
91
+ Object {
92
+ "dependency": "c",
93
+ "name": "b",
94
+ },
95
+ Object {
96
+ "dependency": "a",
97
+ "name": "c",
98
+ },
99
+ ],
100
+ "packages": Array [
101
+ "a",
102
+ "b",
103
+ "c",
104
+ ],
105
+ }
106
+ `);
107
+ });
108
+ });
109
+ function stubPackage(name, deps = []) {
110
+ return {
111
+ name,
112
+ packageJsonPath: `packages/${name}`,
113
+ version: "1.0",
114
+ dependencies: deps.reduce((depMap, dep) => (Object.assign(Object.assign({}, depMap), { [dep]: "*" })), {}),
115
+ devDependencies: {},
116
+ };
117
+ }
@@ -0,0 +1,9 @@
1
+ import { PackageInfos } from "./types/PackageInfo";
2
+ export interface DependencyMap {
3
+ dependencies: Map<string, Set<string>>;
4
+ dependents: Map<string, Set<string>>;
5
+ }
6
+ export declare function createDependencyMap(packages: PackageInfos): {
7
+ dependencies: Map<string, Set<string>>;
8
+ dependents: Map<string, Set<string>>;
9
+ };
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDependencyMap = void 0;
4
+ // @internal
5
+ function createDependencyMap(packages) {
6
+ const map = {
7
+ dependencies: new Map(),
8
+ dependents: new Map(),
9
+ };
10
+ for (const [pkg, info] of Object.entries(packages)) {
11
+ const deps = Object.keys(Object.assign(Object.assign({}, info.dependencies), info.devDependencies));
12
+ for (const dep of deps) {
13
+ if (!map.dependencies.has(pkg)) {
14
+ map.dependencies.set(pkg, new Set());
15
+ }
16
+ map.dependencies.get(pkg).add(dep);
17
+ if (!map.dependents.has(dep)) {
18
+ map.dependents.set(dep, new Set());
19
+ }
20
+ map.dependents.get(dep).add(pkg);
21
+ }
22
+ }
23
+ return map;
24
+ }
25
+ exports.createDependencyMap = createDependencyMap;
@@ -1,6 +1,8 @@
1
1
  import { PackageInfo, PackageInfos } from "./types/PackageInfo";
2
2
  export declare function getDependentMap(packages: PackageInfos): Map<string, Set<string>>;
3
3
  /**
4
+ * @deprecated Do not use
5
+ *
4
6
  * for a package graph of a->b->c (where b depends on a), transitive consumers of a are b & c and their consumers (or what are the consequences of a)
5
7
  * @param targets
6
8
  * @param packages
@@ -8,11 +10,16 @@ export declare function getDependentMap(packages: PackageInfos): Map<string, Set
8
10
  */
9
11
  export declare function getTransitiveConsumers(targets: string[], packages: PackageInfos, scope?: string[]): string[];
10
12
  /**
13
+ * @deprecated Do not use
14
+ *
11
15
  * for a package graph of a->b->c (where b depends on a), transitive providers of c are a & b and their providers (or what is needed to satisfy c)
12
16
  * @param targets
13
17
  * @param packages
14
18
  */
15
19
  export declare function getTransitiveProviders(targets: string[], packages: PackageInfos): string[];
20
+ /** @deprecated Do not use */
16
21
  export declare const getTransitiveDependencies: typeof getTransitiveProviders;
22
+ /** @deprecated Do not use */
17
23
  export declare const getTransitiveDependents: typeof getTransitiveConsumers;
24
+ /** @deprecated Do not use */
18
25
  export declare function getInternalDeps(info: PackageInfo, packages: PackageInfos): string[];
@@ -49,6 +49,8 @@ function getDependentMap(packages) {
49
49
  }
50
50
  exports.getDependentMap = getDependentMap;
51
51
  /**
52
+ * @deprecated Do not use
53
+ *
52
54
  * for a package graph of a->b->c (where b depends on a), transitive consumers of a are b & c and their consumers (or what are the consequences of a)
53
55
  * @param targets
54
56
  * @param packages
@@ -73,6 +75,8 @@ function getTransitiveConsumers(targets, packages, scope = []) {
73
75
  }
74
76
  exports.getTransitiveConsumers = getTransitiveConsumers;
75
77
  /**
78
+ * @deprecated Do not use
79
+ *
76
80
  * for a package graph of a->b->c (where b depends on a), transitive providers of c are a & b and their providers (or what is needed to satisfy c)
77
81
  * @param targets
78
82
  * @param packages
@@ -95,10 +99,11 @@ function getTransitiveProviders(targets, packages) {
95
99
  return [...visited].filter((pkg) => !targets.includes(pkg));
96
100
  }
97
101
  exports.getTransitiveProviders = getTransitiveProviders;
98
- // package dependencies = getting transitive providers
102
+ /** @deprecated Do not use */
99
103
  exports.getTransitiveDependencies = getTransitiveProviders;
100
- // package dependents = getting transitive consumers
104
+ /** @deprecated Do not use */
101
105
  exports.getTransitiveDependents = getTransitiveConsumers;
106
+ /** @deprecated Do not use */
102
107
  function getInternalDeps(info, packages) {
103
108
  const deps = Object.keys(Object.assign(Object.assign({}, info.dependencies), info.devDependencies));
104
109
  return Object.keys(packages).filter((pkg) => deps.includes(pkg));
package/lib/graph.d.ts CHANGED
@@ -1,6 +1,8 @@
1
- import { PackageInfos } from "./types/PackageInfo";
2
- export declare function getPackageGraph(packages: PackageInfos): [string, string][];
3
- /**
4
- * @internal resets the graph cache for internal testing purpose only
5
- */
6
- export declare function _resetGraphCache(): void;
1
+ import type { PackageInfos } from "./types/PackageInfo";
2
+ import type { PackageGraph } from "./types/PackageGraph";
3
+ export interface PackageGraphScope {
4
+ namePatterns?: string[];
5
+ includeDependencies?: boolean;
6
+ includeDependents?: boolean;
7
+ }
8
+ export declare function createPackageGraph(packages: PackageInfos, scope?: PackageGraphScope): PackageGraph;
package/lib/graph.js CHANGED
@@ -1,27 +1,61 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._resetGraphCache = exports.getPackageGraph = void 0;
4
- const dependencies_1 = require("./dependencies");
5
- const graphCache = new Map();
6
- function getPackageGraph(packages) {
7
- if (graphCache.has(packages)) {
8
- return graphCache.get(packages);
9
- }
6
+ exports.createPackageGraph = void 0;
7
+ const createDependencyMap_1 = require("./createDependencyMap");
8
+ const multimatch_1 = __importDefault(require("multimatch"));
9
+ function createPackageGraph(packages, scope = {}) {
10
+ const dependencyMap = (0, createDependencyMap_1.createDependencyMap)(packages);
11
+ const packageSet = new Set();
10
12
  const edges = [];
11
- for (const [pkg, info] of Object.entries(packages)) {
12
- const deps = (0, dependencies_1.getInternalDeps)(info, packages);
13
- for (const dep of deps) {
14
- edges.push([dep, pkg]);
13
+ const visitor = (pkg, dependencies, dependents) => {
14
+ packageSet.add(pkg);
15
+ if (scope.includeDependencies && dependencies) {
16
+ for (const dep of dependencies) {
17
+ edges.push({ name: pkg, dependency: dep });
18
+ packageSet.add(dep);
19
+ }
15
20
  }
16
- }
17
- graphCache.set(packages, edges);
18
- return edges;
21
+ if (scope.includeDependents && dependents) {
22
+ for (const dep of dependents) {
23
+ edges.push({ name: dep, dependency: pkg });
24
+ packageSet.add(dep);
25
+ }
26
+ }
27
+ };
28
+ visitPackageGraph(packages, dependencyMap, visitor, scope);
29
+ return { packages: [...packageSet], dependencies: edges };
19
30
  }
20
- exports.getPackageGraph = getPackageGraph;
21
- /**
22
- * @internal resets the graph cache for internal testing purpose only
23
- */
24
- function _resetGraphCache() {
25
- graphCache.clear();
31
+ exports.createPackageGraph = createPackageGraph;
32
+ function visitPackageGraph(packages, dependencyMap, visitor, scope) {
33
+ var _a, _b;
34
+ const visited = new Set();
35
+ const packageNames = Object.keys(packages);
36
+ const stack = scope && scope.namePatterns ? (0, multimatch_1.default)(packageNames, scope.namePatterns) : packageNames;
37
+ while (stack.length > 0) {
38
+ const pkg = stack.pop();
39
+ if (visited.has(pkg)) {
40
+ continue;
41
+ }
42
+ const nextPkgs = [];
43
+ let dependencies = [];
44
+ let dependents = [];
45
+ if (scope === null || scope === void 0 ? void 0 : scope.includeDependencies) {
46
+ dependencies = [...(_a = dependencyMap.dependencies.get(pkg)) !== null && _a !== void 0 ? _a : []];
47
+ nextPkgs.push(...dependencies);
48
+ }
49
+ if (scope === null || scope === void 0 ? void 0 : scope.includeDependents) {
50
+ dependents = [...(_b = dependencyMap.dependents.get(pkg)) !== null && _b !== void 0 ? _b : []];
51
+ nextPkgs.push(...dependents);
52
+ }
53
+ visitor(pkg, dependencies, dependents);
54
+ visited.add(pkg);
55
+ if (nextPkgs.length > 0) {
56
+ for (const nextPkg of nextPkgs) {
57
+ stack.push(nextPkg);
58
+ }
59
+ }
60
+ }
26
61
  }
27
- exports._resetGraphCache = _resetGraphCache;
@@ -0,0 +1,14 @@
1
+ /** A package graph edge that defines a single package name and one of its dependency */
2
+ export interface PackageDependency {
3
+ name: string;
4
+ dependency: string;
5
+ }
6
+ /** The graph is defined by as a list of package names as nodes, and a list of PackageDependency as edges*/
7
+ export interface PackageGraph {
8
+ packages: string[];
9
+ dependencies: PackageDependency[];
10
+ }
11
+ /** Package graph visitor is called as it visits every package in dependency order */
12
+ export interface PackageGraphVisitor {
13
+ (pkg: string, dependencies: string[], dependents: string[]): void;
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ ;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workspace-tools",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,6 +38,7 @@
38
38
  "@types/yarnpkg__lockfile": "^1.1.3",
39
39
  "beachball": "^2.17.0",
40
40
  "jest": "^25.0.0",
41
+ "prettier": "^2.7.1",
41
42
  "tmp": "^0.2.1",
42
43
  "ts-jest": "^25.5.1",
43
44
  "typedoc": "^0.22.15",