@zeroheight/adoption-cli 2.4.0 → 2.4.3

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.md CHANGED
@@ -1,9 +1,20 @@
1
1
  # Release notes
2
2
 
3
- ## [2.4.0](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.0) - 10th December 2024
3
+ ## [2.4.3](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.3) - 2nd January 2025
4
+
5
+ - `track-package --packages` option can be used to allow tracking specific packages within monorepos in non-interactive mode
6
+
7
+ ## [2.4.2](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.2) - 17th December 2024
8
+
9
+ - Fix issue with parsing pnpm lockfiles using version `6.0`
4
10
 
5
- - `analyze --ignore` option can be used moe than once to allow for more glob patterns, this fixes an issue in **2.3.0** where glob patterns containing commas would not work as expected
11
+ ## [2.4.1](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.1) - 11th December 2024
12
+
13
+ - The `monitor-repo` command now supports custom package naming for projects.
14
+
15
+ ## [2.4.0](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.0) - 10th December 2024
6
16
 
17
+ - `analyze --ignore` option can be used more than once to allow for more glob patterns, this fixes an issue in **2.3.0** where glob patterns containing commas would not work as expected
7
18
 
8
19
  ## [2.3.0](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.3.0) - 5th December 2024
9
20
 
package/README.md CHANGED
@@ -186,6 +186,18 @@ Pass in `false` to disable the interactive mode e.g. when running in a CI enviro
186
186
  zh-adoption track-package --interactive false
187
187
  ```
188
188
 
189
+ `-p` / `--packages`
190
+
191
+ Provide one or multiple package names to match when searching for design system packages. This must be passed when `-in` / `--interactive` is set to `false`.
192
+
193
+ ```bash
194
+ zh-adoption track-package -in false -p package1 -p package2 -p package3
195
+ ```
196
+
197
+ ```bash
198
+ zh-adoption track-package -in false --packages package1,package2,package3
199
+ ```
200
+
189
201
  `--log-level`
190
202
 
191
203
  Provide a severity to output diagnostic messages.
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ const { output, cleanup } = render(React.createElement(HelpInfo, null));
13
13
  program
14
14
  .name("zh-adoption")
15
15
  .description("CLI for measuring design system usage usage in your products")
16
- .version("2.4.0")
16
+ .version("2.4.3")
17
17
  .addHelpText("before", output)
18
18
  .option("--log-file <path>", "Path to write logs to, if not provided logs only error logs will be written to stderr")
19
19
  .addOption(new Option("--log-level <level>", "The lowest level of logs to display")
@@ -3,6 +3,7 @@ import { RenderOptions } from "ink";
3
3
  interface MonitorRepoOptions {
4
4
  interactive: boolean;
5
5
  dir?: string[];
6
+ packageName?: string;
6
7
  }
7
8
  export declare function monitorRepoAction(options: MonitorRepoOptions, _renderOptions?: RenderOptions): Promise<void>;
8
9
  export declare function monitorRepoCommand(): Command;
@@ -8,7 +8,7 @@ export async function monitorRepoAction(options, _renderOptions) {
8
8
  // if (options.interactive) {
9
9
  // render(<MonitorRepo />, renderOptions);
10
10
  // } else {
11
- render(React.createElement(NonInteractiveMonitorRepo, { packageDirs: options.dir }));
11
+ render(React.createElement(NonInteractiveMonitorRepo, { packageDirs: options.dir, packageName: options.packageName }));
12
12
  // }
13
13
  }
14
14
  export function monitorRepoCommand() {
@@ -28,6 +28,7 @@ export function monitorRepoCommand() {
28
28
  // .argParser((value) => yn(value))
29
29
  // )
30
30
  .addOption(new Option("-d, --dir <path...>", "use package directory to find package.json and lockfile"))
31
+ .addOption(new Option("-p, --package-name <name>", "specify the name used to identify the package in zeroheight"))
31
32
  .action(async (options) => {
32
33
  setStdErrStream();
33
34
  try {
@@ -2,6 +2,7 @@ import { Command } from "commander";
2
2
  import { RenderOptions } from "ink";
3
3
  interface TrackPackageOptions {
4
4
  interactive: boolean;
5
+ packages?: string[];
5
6
  }
6
7
  export declare function trackPackageAction(options: TrackPackageOptions, renderOptions?: RenderOptions): Promise<void>;
7
8
  export declare function trackPackageCommand(): Command;
@@ -5,12 +5,13 @@ import yn from "yn";
5
5
  import NonInteractiveTrackPackage from "../components/track-package/non-interactive-track-package.js";
6
6
  import TrackPackage from "../components/track-package/track-package.js";
7
7
  import { setStdErrStream } from "../common/logging.js";
8
+ import { parsePackageList } from "./track-package.utils.js";
8
9
  export async function trackPackageAction(options, renderOptions) {
9
10
  if (options.interactive) {
10
11
  render(React.createElement(TrackPackage, null), renderOptions);
11
12
  }
12
13
  else {
13
- render(React.createElement(NonInteractiveTrackPackage, null));
14
+ render(React.createElement(NonInteractiveTrackPackage, { allowedPackages: options.packages }));
14
15
  }
15
16
  }
16
17
  export function trackPackageCommand() {
@@ -24,6 +25,7 @@ export function trackPackageCommand() {
24
25
  .addOption(new Option("-in, --interactive [boolean]", "disable to skip manual input (useful when running in CI)")
25
26
  .default(true)
26
27
  .argParser((value) => yn(value)))
28
+ .addOption(new Option("-p, --packages [packageNames]", "specify the packages to search for, use multiple times to match more than one package").argParser(parsePackageList))
27
29
  .action(async (options) => {
28
30
  if (!options.interactive) {
29
31
  setStdErrStream();
@@ -4,7 +4,14 @@ import { PackageFile } from "../common/types/package-file.js";
4
4
  * @param subpath - provide to search inside subpath instead of working directory
5
5
  */
6
6
  export declare function findPackageFiles(subpath?: string): Promise<string[]>;
7
- export declare function getPackageInfo(): Promise<{
7
+ /**
8
+ * Get allowed package files from the directory and return
9
+ * their name/package/version/exports
10
+ *
11
+ * @param allowedPackages a list of package names to match on
12
+ * @returns a list of matched packages files and errors
13
+ */
14
+ export declare function getPackageInfo(allowedPackages?: string[]): Promise<{
8
15
  files: PackageFile[];
9
16
  error: string | null;
10
17
  }>;
@@ -12,3 +19,7 @@ export declare function getPackageInfo(): Promise<{
12
19
  * Transform exports object into fully qualified aliases
13
20
  */
14
21
  export declare function getAliasesFromExports(packageName: string, exports?: PackageFile["exports"]): string[];
22
+ /**
23
+ * Parse package list and format correctly
24
+ */
25
+ export declare function parsePackageList(value: string, previous?: string[]): string[];
@@ -9,7 +9,14 @@ export async function findPackageFiles(subpath) {
9
9
  const workingDir = joinPath(process.cwd(), subpath ?? "");
10
10
  return findFiles(workingDir, "**/**/package.json", []);
11
11
  }
12
- export async function getPackageInfo() {
12
+ /**
13
+ * Get allowed package files from the directory and return
14
+ * their name/package/version/exports
15
+ *
16
+ * @param allowedPackages a list of package names to match on
17
+ * @returns a list of matched packages files and errors
18
+ */
19
+ export async function getPackageInfo(allowedPackages) {
13
20
  const base = process.cwd();
14
21
  const files = await findPackageFiles();
15
22
  if (files.length === 0) {
@@ -19,16 +26,25 @@ export async function getPackageInfo() {
19
26
  };
20
27
  }
21
28
  try {
22
- const packageFiles = await Promise.all(files.map(async (file) => {
29
+ let packageFiles = await Promise.all(files.map(async (file) => {
23
30
  const fileContents = await readFile(file, "utf-8");
24
31
  const parsedPackage = JSON.parse(fileContents);
25
32
  return {
26
33
  name: parsedPackage.name,
27
- path: `.${files[0]?.split(base).pop()}`,
34
+ path: `.${file.split(base).pop()}`,
28
35
  version: parsedPackage.version,
29
36
  exports: parsedPackage.exports,
30
37
  };
31
38
  }));
39
+ if (allowedPackages?.length) {
40
+ packageFiles = packageFiles.filter((pack) => allowedPackages.includes(pack.name));
41
+ if (!packageFiles.length) {
42
+ return {
43
+ files: [],
44
+ error: "Can't find any matching packages",
45
+ };
46
+ }
47
+ }
32
48
  return {
33
49
  files: packageFiles,
34
50
  error: null,
@@ -51,3 +67,15 @@ export function getAliasesFromExports(packageName, exports) {
51
67
  .map((path) => joinPath(packageName, path))
52
68
  .filter((name) => name !== packageName);
53
69
  }
70
+ /**
71
+ * Parse package list and format correctly
72
+ */
73
+ export function parsePackageList(value, previous = []) {
74
+ return [
75
+ ...previous,
76
+ ...value
77
+ .split(",")
78
+ .map((entry) => entry.trim())
79
+ .filter(Boolean),
80
+ ];
81
+ }
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  interface NonInteractiveMonitorRepoProps {
3
3
  packageDirs?: string[];
4
+ packageName?: string;
4
5
  }
5
- export default function NonInteractiveMonitorRepo({ packageDirs, }: NonInteractiveMonitorRepoProps): React.JSX.Element;
6
+ export default function NonInteractiveMonitorRepo({ packageDirs, packageName, }: NonInteractiveMonitorRepoProps): React.JSX.Element;
6
7
  export {};
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
2
  import { Box, Text } from "ink";
3
3
  import Spinner from "ink-spinner";
4
- import { join as joinPath } from "path";
4
+ import { basename, join as joinPath } from "path";
5
5
  import { findLockfiles, getPackageMeta, groupByBasename, parseLockfile, } from "../../commands/monitor-repo.utils.js";
6
6
  import { findPackageFiles } from "../../commands/track-package.utils.js";
7
7
  import { ResponseStatus, submitMonitoredRepoDetails, } from "../../common/api.js";
@@ -15,7 +15,7 @@ var Step;
15
15
  Step[Step["FINDING_DETAILS"] = 2] = "FINDING_DETAILS";
16
16
  Step[Step["SENDING_DATA"] = 3] = "SENDING_DATA";
17
17
  })(Step || (Step = {}));
18
- export default function NonInteractiveMonitorRepo({ packageDirs, }) {
18
+ export default function NonInteractiveMonitorRepo({ packageDirs, packageName, }) {
19
19
  const [errorMessage, setErrorMessage] = React.useState(); // Global error message
20
20
  const [repoStatus, setRepoStatus] = React.useState({});
21
21
  function updateRepoStatus(name, step, error) {
@@ -51,6 +51,13 @@ export default function NonInteractiveMonitorRepo({ packageDirs, }) {
51
51
  let packageMeta;
52
52
  try {
53
53
  packageMeta = await getPackageMeta(joinPath(directory, "package.json"));
54
+ if (packageName) {
55
+ packageMeta.name = packageName;
56
+ }
57
+ if (!packageMeta.name) {
58
+ setErrorMessage(`Name field is missing in your ${basename(directory)}/package.json file. Re-run the command with --package-name <name> to continue.`);
59
+ continue;
60
+ }
54
61
  }
55
62
  catch (e) {
56
63
  // package.json doesn't exist or is invalid, skip pair
@@ -1,2 +1,5 @@
1
1
  import React from "react";
2
- export default function NonInteractiveTrackPackage(): React.JSX.Element;
2
+ export interface NonInteractiveTrackPackageProps {
3
+ allowedPackages?: string[];
4
+ }
5
+ export default function NonInteractiveTrackPackage({ allowedPackages, }: NonInteractiveTrackPackageProps): React.JSX.Element;
@@ -13,7 +13,7 @@ var Step;
13
13
  Step[Step["MULTIPLE_PACKAGES_FOUND"] = 3] = "MULTIPLE_PACKAGES_FOUND";
14
14
  Step[Step["SINGLE_PACKAGE_FOUND"] = 4] = "SINGLE_PACKAGE_FOUND";
15
15
  })(Step || (Step = {}));
16
- export default function NonInteractiveTrackPackage() {
16
+ export default function NonInteractiveTrackPackage({ allowedPackages, }) {
17
17
  const { exit } = useApp();
18
18
  const [currentStep, setCurrentStep] = React.useState(Step.FINDING_DETAILS);
19
19
  const [errorMessage, setErrorMessage] = React.useState(null);
@@ -22,7 +22,7 @@ export default function NonInteractiveTrackPackage() {
22
22
  const [packageVersion, setPackageVersion] = React.useState(null);
23
23
  async function runTrackPackage() {
24
24
  const config = (await readConfig()) ?? { token: "temp", client: "temp" };
25
- const { files, error } = await getPackageInfo();
25
+ const { files, error } = await getPackageInfo(allowedPackages);
26
26
  try {
27
27
  if (files.length === 1) {
28
28
  const { name, path, version, exports } = files[0];
@@ -83,7 +83,7 @@ export default function NonInteractiveTrackPackage() {
83
83
  " searching for package file...")),
84
84
  currentStep === Step.SINGLE_PACKAGE_FOUND && (React.createElement(React.Fragment, null,
85
85
  React.createElement(Text, null,
86
- React.createElement(Text, { color: "green" }, "Details founds:"),
86
+ React.createElement(Text, { color: "green" }, "Details found:"),
87
87
  " ",
88
88
  packageName,
89
89
  "@",
@@ -37,7 +37,13 @@ _PNPMLockParser_instances = new WeakSet(), _PNPMLockParser_parseV5 = function _P
37
37
  }, _PNPMLockParser_parseV6 = function _PNPMLockParser_parseV6(data) {
38
38
  return Object.keys(data.packages)
39
39
  .map((packagePair) => {
40
- const [name, version] = packagePair.split("@");
40
+ const lastIndex = packagePair.lastIndexOf("@");
41
+ let name = packagePair.slice(0, lastIndex);
42
+ const version = packagePair.slice(lastIndex + 1);
43
+ // v6 lockfiles have a leading slash
44
+ if (name.startsWith("/")) {
45
+ name = name.slice(1);
46
+ }
41
47
  return { name, version };
42
48
  })
43
49
  .filter((p) => p.name && p.version);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroheight/adoption-cli",
3
- "version": "2.4.0",
3
+ "version": "2.4.3",
4
4
  "license": "ISC",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {