@zeroheight/adoption-cli 2.3.0 → 2.4.2
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 +12 -0
- package/README.md +12 -0
- package/dist/cli.js +1 -1
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +8 -4
- package/dist/commands/analyze.utils.d.ts +7 -2
- package/dist/commands/analyze.utils.js +15 -3
- package/dist/commands/monitor-repo.d.ts +1 -0
- package/dist/commands/monitor-repo.js +2 -1
- package/dist/commands/monitor-repo.utils.js +1 -1
- package/dist/commands/track-package.utils.js +1 -1
- package/dist/components/monitor-repo/non-interactive-monitor-repo.d.ts +2 -1
- package/dist/components/monitor-repo/non-interactive-monitor-repo.js +9 -2
- package/dist/lockfile-parsers/pnpm-lock-parser.js +7 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## [2.4.2](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.2) - 17th December 2024
|
|
4
|
+
|
|
5
|
+
- Fix issue with parsing pnpm lockfiles using version `6.0`
|
|
6
|
+
|
|
7
|
+
## [2.4.1](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.1) - 11th December 2024
|
|
8
|
+
|
|
9
|
+
- The monitor-repo command now supports custom package naming for projects.
|
|
10
|
+
|
|
11
|
+
## [2.4.0](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.4.0) - 10th December 2024
|
|
12
|
+
|
|
13
|
+
- `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
|
|
14
|
+
|
|
3
15
|
## [2.3.0](https://www.npmjs.com/package/@zeroheight/adoption-cli/v/2.3.0) - 5th December 2024
|
|
4
16
|
|
|
5
17
|
- The `analyze` command now ignores `*.d.ts` files by default, alongside `*.test.*` and `*.spec.*` files.
|
package/README.md
CHANGED
|
@@ -78,6 +78,18 @@ Provide a glob pattern to ignore files, directories or file extensions when sear
|
|
|
78
78
|
zh-adoption analyze -i "**/*.{test,spec}.*"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
To pass multiple patterns, use the option multiple times e.g.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
zh-adoption analyze -i "**/*.{test,spec}.*" -i "**/*.d.ts"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
To ignore nothing, even the default patterns (`['**/*.{test,spec}.*', '**/*.d.ts']`), pass an empty value
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
zh-adoption analyze -i
|
|
91
|
+
```
|
|
92
|
+
|
|
81
93
|
`-r` / `--repo-name`
|
|
82
94
|
|
|
83
95
|
Provide a name for the current repository. This must be passed when `-in` / `--interactive` is set to `false`.
|
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.
|
|
16
|
+
.version("2.4.2")
|
|
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")
|
package/dist/commands/analyze.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
import { render } from "ink";
|
|
3
3
|
import { Command, Option } from "commander";
|
|
4
4
|
import yn from "yn";
|
|
5
|
-
import { analyzeFiles } from "./analyze.utils.js";
|
|
5
|
+
import { analyzeFiles, parseGlobList } from "./analyze.utils.js";
|
|
6
6
|
import Analyze from "../components/analyze/analyze.js";
|
|
7
7
|
import NonInteractiveAnalyze from "../components/analyze/non-interactive-analyze.js";
|
|
8
8
|
import logger, { setStdErrStream } from "../common/logging.js";
|
|
@@ -23,7 +23,9 @@ export function analyzeCommand() {
|
|
|
23
23
|
showGlobalOptions: true,
|
|
24
24
|
})
|
|
25
25
|
.addOption(new Option("-e, --extensions [ext]", "file extensions to include when searching for components").default("**/*.{js,jsx,ts,tsx}", "glob pattern to determine file extensions"))
|
|
26
|
-
.addOption(new Option("-i, --ignore [
|
|
26
|
+
.addOption(new Option("-i, --ignore [patterns]", "files to ignore when searching for components, use multiple times to add more than one glob pattern")
|
|
27
|
+
.default(["**/*.{test,spec}.*", "**/*.d.ts"], "*.test.*, *.spec.* and *.d.ts files")
|
|
28
|
+
.argParser(parseGlobList))
|
|
27
29
|
.addOption(new Option("-d, --dry-run", "don't push results to zeroheight").default(false))
|
|
28
30
|
.addOption(new Option("-r, --repo-name <string>", "name of the repository"))
|
|
29
31
|
.addOption(new Option("-in, --interactive [boolean]", "disable to skip input (useful when running in CI)")
|
|
@@ -33,8 +35,10 @@ export function analyzeCommand() {
|
|
|
33
35
|
if (!options.interactive) {
|
|
34
36
|
setStdErrStream();
|
|
35
37
|
}
|
|
38
|
+
// If no option is passed in aka `true`, use empty list of ignore patterns
|
|
39
|
+
const ignorePattern = typeof options.ignore === "boolean" ? [] : options.ignore;
|
|
36
40
|
try {
|
|
37
|
-
await analyzeAction(options);
|
|
41
|
+
await analyzeAction({ ...options, ignore: ignorePattern });
|
|
38
42
|
}
|
|
39
43
|
catch (e) {
|
|
40
44
|
logger.error({ error: e }, "Unhandled exception running analyze command");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Option } from "commander";
|
|
1
2
|
import { RawUsageMap } from "./analyze.js";
|
|
2
3
|
import { ComponentProps } from "../ast/analyze.js";
|
|
3
4
|
export interface ComponentUsageRecord {
|
|
@@ -15,9 +16,13 @@ export interface ComponentUsageRecord {
|
|
|
15
16
|
* @param gitIgnore contents of .gitignore file
|
|
16
17
|
* @returns list of file paths
|
|
17
18
|
*/
|
|
18
|
-
export declare function findFiles(base: string, extensions: string, ignorePattern: string
|
|
19
|
-
export declare function analyzeFiles(extensions: string, ignorePattern: string): Promise<{
|
|
19
|
+
export declare function findFiles(base: string, extensions: string, ignorePattern: string[]): Promise<string[]>;
|
|
20
|
+
export declare function analyzeFiles(extensions: string, ignorePattern: string[]): Promise<{
|
|
20
21
|
errorFile: string | null;
|
|
21
22
|
usage: RawUsageMap;
|
|
22
23
|
}>;
|
|
23
24
|
export declare function calculateNumberOfComponents(usageResult: RawUsageMap): number;
|
|
25
|
+
/**
|
|
26
|
+
* Parse the ignore array and format correctly
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseGlobList(this: Option, value: string, previous: unknown): any[];
|
|
@@ -16,8 +16,6 @@ import logger from "../common/logging.js";
|
|
|
16
16
|
*/
|
|
17
17
|
export async function findFiles(base, extensions, ignorePattern) {
|
|
18
18
|
const gitIgnore = await getGitIgnore(base);
|
|
19
|
-
// Split by comma if string exists otherwise it could be a boolean flag
|
|
20
|
-
const ignorePatternArray = typeof ignorePattern === "string" ? ignorePattern.split(",") : [];
|
|
21
19
|
// typescript complains about the ignore() function having
|
|
22
20
|
// no call signature. Could not find a way to fix this.
|
|
23
21
|
// @ts-ignore
|
|
@@ -32,7 +30,7 @@ export async function findFiles(base, extensions, ignorePattern) {
|
|
|
32
30
|
const matchingFiles = [];
|
|
33
31
|
const g = new Glob(extensions, {
|
|
34
32
|
cwd: base,
|
|
35
|
-
ignore:
|
|
33
|
+
ignore: ignorePattern,
|
|
36
34
|
fs,
|
|
37
35
|
});
|
|
38
36
|
for await (const file of g) {
|
|
@@ -103,3 +101,17 @@ export function calculateNumberOfComponents(usageResult) {
|
|
|
103
101
|
}
|
|
104
102
|
return 0;
|
|
105
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Parse the ignore array and format correctly
|
|
106
|
+
*/
|
|
107
|
+
export function parseGlobList(value, previous) {
|
|
108
|
+
// Ignore default values if option given instead
|
|
109
|
+
if (previous == this.defaultValue) {
|
|
110
|
+
return [value];
|
|
111
|
+
}
|
|
112
|
+
// Concat to array if array already exists
|
|
113
|
+
if (Array.isArray(previous)) {
|
|
114
|
+
return previous.concat(value);
|
|
115
|
+
}
|
|
116
|
+
return [value];
|
|
117
|
+
}
|
|
@@ -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 {
|
|
@@ -40,7 +40,7 @@ export async function parseLockfile(lockfilePath) {
|
|
|
40
40
|
*/
|
|
41
41
|
export async function findLockfiles(subpath) {
|
|
42
42
|
const workingDir = joinPath(process.cwd(), subpath ?? "");
|
|
43
|
-
return findFiles(workingDir, "**/**/{package-lock.json,shrinkwrap.yaml,pnpm-lock.yaml,yarn.lock}",
|
|
43
|
+
return findFiles(workingDir, "**/**/{package-lock.json,shrinkwrap.yaml,pnpm-lock.yaml,yarn.lock}", []);
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Get the lockfile parser so name, version and packages can be extracted from the lockfile
|
|
@@ -7,7 +7,7 @@ import { findFiles } from "./analyze.utils.js";
|
|
|
7
7
|
*/
|
|
8
8
|
export async function findPackageFiles(subpath) {
|
|
9
9
|
const workingDir = joinPath(process.cwd(), subpath ?? "");
|
|
10
|
-
return findFiles(workingDir, "**/**/package.json",
|
|
10
|
+
return findFiles(workingDir, "**/**/package.json", []);
|
|
11
11
|
}
|
|
12
12
|
export async function getPackageInfo() {
|
|
13
13
|
const base = process.cwd();
|
|
@@ -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
|
|
@@ -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
|
|
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);
|