workspace-tools 0.19.3 → 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,52 @@
2
2
  "name": "workspace-tools",
3
3
  "entries": [
4
4
  {
5
- "date": "Thu, 23 Jun 2022 19:10:01 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",
21
+ "tag": "workspace-tools_v0.20.0",
22
+ "version": "0.20.0",
23
+ "comments": {
24
+ "minor": [
25
+ {
26
+ "author": "elcraig@microsoft.com",
27
+ "package": "workspace-tools",
28
+ "comment": "BREAKING: Remove getChangePath because it's specific to beachball and should be defined there",
29
+ "commit": "bbfc44143e2f2bc0ca17bf5c351bab52fe8c9025"
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "date": "Thu, 23 Jun 2022 19:53:03 GMT",
36
+ "tag": "workspace-tools_v0.19.4",
37
+ "version": "0.19.4",
38
+ "comments": {
39
+ "patch": [
40
+ {
41
+ "author": "elcraig@microsoft.com",
42
+ "package": "workspace-tools",
43
+ "comment": "Add findProjectRoot path helper",
44
+ "commit": "5ad6577811656ad23cf567f0996cf9b70d8c23a0"
45
+ }
46
+ ]
47
+ }
48
+ },
49
+ {
50
+ "date": "Thu, 23 Jun 2022 19:10:04 GMT",
6
51
  "tag": "workspace-tools_v0.19.3",
7
52
  "version": "0.19.3",
8
53
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,36 @@
1
1
  # Change Log - workspace-tools
2
2
 
3
- This log was last generated on Thu, 23 Jun 2022 19:10:01 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
+
15
+ ## 0.20.0
16
+
17
+ Thu, 23 Jun 2022 20:24:15 GMT
18
+
19
+ ### Minor changes
20
+
21
+ - BREAKING: Remove getChangePath because it's specific to beachball and should be defined there (elcraig@microsoft.com)
22
+
23
+ ## 0.19.4
24
+
25
+ Thu, 23 Jun 2022 19:53:03 GMT
26
+
27
+ ### Patches
28
+
29
+ - Add findProjectRoot path helper (elcraig@microsoft.com)
30
+
7
31
  ## 0.19.3
8
32
 
9
- Thu, 23 Jun 2022 19:10:01 GMT
33
+ Thu, 23 Jun 2022 19:10:04 GMT
10
34
 
11
35
  ### Patches
12
36
 
@@ -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;
package/lib/paths.d.ts CHANGED
@@ -1,10 +1,18 @@
1
1
  /**
2
- * Starting from `cwd`, searches up the directory hierarchy for `pathName`
3
- * @param pathName
4
- * @param cwd
2
+ * Starting from `cwd`, searches up the directory hierarchy for `pathName`.
5
3
  */
6
4
  export declare function searchUp(pathName: string, cwd: string): string | null;
5
+ /**
6
+ * Starting from `cwd`, searches up the directory hierarchy for `.git`.
7
+ */
7
8
  export declare function findGitRoot(cwd: string): string | null;
9
+ /**
10
+ * Starting from `cwd`, searches up the directory hierarchy for `package.json`.
11
+ */
8
12
  export declare function findPackageRoot(cwd: string): string | null;
9
- export declare function getChangePath(cwd: string): string | null;
13
+ /**
14
+ * Starting from `cwd`, searches up the directory hierarchy for the workspace root,
15
+ * falling back to the git root if no workspace is detected.
16
+ */
17
+ export declare function findProjectRoot(cwd: string): string | null;
10
18
  export declare function isChildOf(child: string, parent: string): boolean;
package/lib/paths.js CHANGED
@@ -3,13 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isChildOf = exports.getChangePath = exports.findPackageRoot = exports.findGitRoot = exports.searchUp = void 0;
6
+ exports.isChildOf = exports.findProjectRoot = exports.findPackageRoot = exports.findGitRoot = exports.searchUp = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
+ const getWorkspaceRoot_1 = require("./workspaces/getWorkspaceRoot");
9
10
  /**
10
- * Starting from `cwd`, searches up the directory hierarchy for `pathName`
11
- * @param pathName
12
- * @param cwd
11
+ * Starting from `cwd`, searches up the directory hierarchy for `pathName`.
13
12
  */
14
13
  function searchUp(pathName, cwd) {
15
14
  const root = path_1.default.parse(cwd).root;
@@ -27,22 +26,33 @@ function searchUp(pathName, cwd) {
27
26
  return null;
28
27
  }
29
28
  exports.searchUp = searchUp;
29
+ /**
30
+ * Starting from `cwd`, searches up the directory hierarchy for `.git`.
31
+ */
30
32
  function findGitRoot(cwd) {
31
- return searchUp('.git', cwd);
33
+ return searchUp(".git", cwd);
32
34
  }
33
35
  exports.findGitRoot = findGitRoot;
36
+ /**
37
+ * Starting from `cwd`, searches up the directory hierarchy for `package.json`.
38
+ */
34
39
  function findPackageRoot(cwd) {
35
- return searchUp('package.json', cwd);
40
+ return searchUp("package.json", cwd);
36
41
  }
37
42
  exports.findPackageRoot = findPackageRoot;
38
- function getChangePath(cwd) {
39
- const gitRoot = findGitRoot(cwd);
40
- if (gitRoot) {
41
- return path_1.default.join(gitRoot, 'change');
43
+ /**
44
+ * Starting from `cwd`, searches up the directory hierarchy for the workspace root,
45
+ * falling back to the git root if no workspace is detected.
46
+ */
47
+ function findProjectRoot(cwd) {
48
+ let workspaceRoot;
49
+ try {
50
+ workspaceRoot = (0, getWorkspaceRoot_1.getWorkspaceRoot)(cwd);
42
51
  }
43
- return null;
52
+ catch (_a) { }
53
+ return workspaceRoot || findGitRoot(cwd);
44
54
  }
45
- exports.getChangePath = getChangePath;
55
+ exports.findProjectRoot = findProjectRoot;
46
56
  function isChildOf(child, parent) {
47
57
  const relativePath = path_1.default.relative(child, parent);
48
58
  return /^[.\/\\]+$/.test(relativePath);
@@ -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.19.3",
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",