@code-pushup/utils 0.53.1 → 0.55.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/index.js CHANGED
@@ -29,7 +29,7 @@ function exists(value) {
29
29
  return value != null;
30
30
  }
31
31
  function getMissingRefsForCategories(categories, plugins) {
32
- if (categories.length === 0) {
32
+ if (!categories || categories.length === 0) {
33
33
  return false;
34
34
  }
35
35
  const auditRefsFromCategory = categories.flatMap(
@@ -106,7 +106,6 @@ var fileNameSchema = z.string().trim().regex(filenameRegex, {
106
106
  message: `The filename has to be valid`
107
107
  }).min(1, { message: "file name is invalid" });
108
108
  var positiveIntSchema = z.number().int().positive();
109
- var nonnegativeIntSchema = z.number().int().nonnegative();
110
109
  var nonnegativeNumberSchema = z.number().nonnegative();
111
110
  function packageVersionSchema(options) {
112
111
  const { versionDescription = "NPM version of the package", required } = options ?? {};
@@ -529,12 +528,9 @@ var unrefinedCoreConfigSchema = z14.object({
529
528
  var coreConfigSchema = refineCoreConfig(unrefinedCoreConfigSchema);
530
529
  function refineCoreConfig(schema) {
531
530
  return schema.refine(
532
- (coreCfg) => !getMissingRefsForCategories(coreCfg.categories ?? [], coreCfg.plugins),
533
- (coreCfg) => ({
534
- message: missingRefsForCategoriesErrorMsg(
535
- coreCfg.categories ?? [],
536
- coreCfg.plugins
537
- )
531
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
532
+ ({ categories, plugins }) => ({
533
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
538
534
  })
539
535
  );
540
536
  }
@@ -586,19 +582,16 @@ var reportSchema = packageVersionSchema({
586
582
  ).merge(
587
583
  z15.object(
588
584
  {
589
- categories: z15.array(categoryConfigSchema),
590
585
  plugins: z15.array(pluginReportSchema).min(1),
586
+ categories: z15.array(categoryConfigSchema).optional(),
591
587
  commit: commitSchema.describe("Git commit for which report was collected").nullable()
592
588
  },
593
589
  { description: "Collect output data" }
594
590
  )
595
591
  ).refine(
596
- (report) => !getMissingRefsForCategories(report.categories, report.plugins),
597
- (report) => ({
598
- message: missingRefsForCategoriesErrorMsg(
599
- report.categories,
600
- report.plugins
601
- )
592
+ ({ categories, plugins }) => !getMissingRefsForCategories(categories, plugins),
593
+ ({ categories, plugins }) => ({
594
+ message: missingRefsForCategoriesErrorMsg(categories, plugins)
602
595
  })
603
596
  );
604
597
 
@@ -650,7 +643,7 @@ var auditDiffSchema = scorableWithPluginDiffSchema.merge(
650
643
  z16.object({
651
644
  values: makeComparisonSchema(auditValueSchema).merge(
652
645
  z16.object({
653
- diff: z16.number().int().describe("Value change (`values.after - values.before`)")
646
+ diff: z16.number().describe("Value change (`values.after - values.before`)")
654
647
  })
655
648
  ).describe("Audit `value` comparison"),
656
649
  displayValues: makeComparisonSchema(auditDisplayValueSchema).describe(
@@ -997,6 +990,7 @@ function executeProcess(cfg) {
997
990
  return new Promise((resolve, reject) => {
998
991
  const spawnedProcess = spawn(command, args ?? [], {
999
992
  shell: true,
993
+ windowsHide: true,
1000
994
  ...options
1001
995
  });
1002
996
  let stdout = "";
@@ -1030,7 +1024,7 @@ function executeProcess(cfg) {
1030
1024
  import { bold, gray } from "ansis";
1031
1025
  import { bundleRequire } from "bundle-require";
1032
1026
  import { mkdir, readFile, readdir, rm, stat } from "node:fs/promises";
1033
- import { join } from "node:path";
1027
+ import { dirname, join } from "node:path";
1034
1028
 
1035
1029
  // packages/utils/src/lib/formatting.ts
1036
1030
  function slugify(text) {
@@ -1267,6 +1261,16 @@ async function crawlFileSystem(options) {
1267
1261
  const resultsNestedArray = await Promise.all(promises);
1268
1262
  return resultsNestedArray.flat();
1269
1263
  }
1264
+ async function findNearestFile(fileNames, cwd = process.cwd()) {
1265
+ for (let directory = cwd; directory !== dirname(directory); directory = dirname(directory)) {
1266
+ for (const file of fileNames) {
1267
+ if (await fileExists(join(directory, file))) {
1268
+ return join(directory, file);
1269
+ }
1270
+ }
1271
+ }
1272
+ return void 0;
1273
+ }
1270
1274
  function findLineNumberInText(content, pattern) {
1271
1275
  const lines = content.split(/\r?\n/);
1272
1276
  const lineNumber = lines.findIndex((line) => line.includes(pattern)) + 1;
@@ -2097,7 +2101,7 @@ function getSortableGroupByRef({ plugin, slug, weight }, plugins) {
2097
2101
  }
2098
2102
  function sortReport(report) {
2099
2103
  const { categories, plugins } = report;
2100
- const sortedCategories = categories.map((category) => {
2104
+ const sortedCategories = categories?.map((category) => {
2101
2105
  const { audits, groups } = category.refs.reduce(
2102
2106
  (acc, ref) => ({
2103
2107
  ...acc,
@@ -2237,14 +2241,15 @@ function auditDetailsAuditValue({
2237
2241
  String(displayValue ?? value)
2238
2242
  )} (score: ${formatReportScore(score)})`;
2239
2243
  }
2244
+ function hasCategories(report) {
2245
+ return !!report.categories && report.categories.length > 0;
2246
+ }
2240
2247
  function generateMdReport(report, options) {
2241
- return new MarkdownDocument3().heading(HIERARCHY.level_1, REPORT_HEADLINE_TEXT).$if(
2242
- report.categories.length > 0,
2243
- (doc) => doc.$concat(
2244
- categoriesOverviewSection(report),
2245
- categoriesDetailsSection(report)
2246
- )
2247
- ).$concat(auditsSection(report, options), aboutSection(report)).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
2248
+ return new MarkdownDocument3().heading(HIERARCHY.level_1, REPORT_HEADLINE_TEXT).$concat(
2249
+ ...hasCategories(report) ? [categoriesOverviewSection(report), categoriesDetailsSection(report)] : [],
2250
+ auditsSection(report, options),
2251
+ aboutSection(report)
2252
+ ).rule().paragraph(md4`${FOOTER_PREFIX} ${md4.link(README_LINK, "Code PushUp")}`).toString();
2248
2253
  }
2249
2254
  function auditDetailsIssues(issues = [], options) {
2250
2255
  if (issues.length === 0) {
@@ -2346,7 +2351,7 @@ function reportMetaTable({
2346
2351
  md4.code(version),
2347
2352
  formatDuration(duration),
2348
2353
  plugins.length.toString(),
2349
- categories.length.toString(),
2354
+ (categories?.length ?? 0).toString(),
2350
2355
  plugins.reduce((acc, { audits }) => acc + audits.length, 0).toString()
2351
2356
  ]
2352
2357
  ]
@@ -2678,24 +2683,26 @@ function log(msg = "") {
2678
2683
  ui().logger.log(msg);
2679
2684
  }
2680
2685
  function logStdoutSummary(report, verbose = false) {
2681
- const printCategories = report.categories.length > 0;
2682
- log(reportToHeaderSection(report));
2686
+ const { plugins, categories, packageName, version } = report;
2687
+ log(reportToHeaderSection({ packageName, version }));
2683
2688
  log();
2684
- logPlugins(report.plugins, verbose);
2685
- if (printCategories) {
2686
- logCategories(report);
2689
+ logPlugins(plugins, verbose);
2690
+ if (categories && categories.length > 0) {
2691
+ logCategories({ plugins, categories });
2687
2692
  }
2688
2693
  log(`${FOOTER_PREFIX} ${CODE_PUSHUP_DOMAIN}`);
2689
2694
  log();
2690
2695
  }
2691
- function reportToHeaderSection(report) {
2692
- const { packageName, version } = report;
2696
+ function reportToHeaderSection({
2697
+ packageName,
2698
+ version
2699
+ }) {
2693
2700
  return `${bold4(REPORT_HEADLINE_TEXT)} - ${packageName}@${version}`;
2694
2701
  }
2695
2702
  function logPlugins(plugins, verbose) {
2696
2703
  plugins.forEach((plugin) => {
2697
2704
  const { title, audits } = plugin;
2698
- const filteredAudits = verbose ? audits : audits.filter(({ score }) => score !== 1);
2705
+ const filteredAudits = verbose || audits.length === 1 ? audits : audits.filter(({ score }) => score !== 1);
2699
2706
  const diff = audits.length - filteredAudits.length;
2700
2707
  logAudits(title, filteredAudits);
2701
2708
  if (diff > 0) {
@@ -2735,7 +2742,10 @@ function logRow(score, title, value) {
2735
2742
  ] : []
2736
2743
  ]);
2737
2744
  }
2738
- function logCategories({ categories, plugins }) {
2745
+ function logCategories({
2746
+ plugins,
2747
+ categories
2748
+ }) {
2739
2749
  const hAlign = (idx) => idx === 0 ? "left" : "right";
2740
2750
  const rows = categories.map(({ title, score, refs, isBinary }) => [
2741
2751
  title,
@@ -2817,7 +2827,7 @@ function scoreReport(report) {
2817
2827
  }
2818
2828
  return item.score;
2819
2829
  }
2820
- const scoredCategories = report.categories.map((category) => ({
2830
+ const scoredCategories = report.categories?.map((category) => ({
2821
2831
  ...category,
2822
2832
  score: calculateScore(category.refs, catScoreFn)
2823
2833
  }));
@@ -2904,6 +2914,7 @@ export {
2904
2914
  filePathToCliArg,
2905
2915
  filterItemRefsBy,
2906
2916
  findLineNumberInText,
2917
+ findNearestFile,
2907
2918
  formatBytes,
2908
2919
  formatDuration,
2909
2920
  formatGitPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/utils",
3
- "version": "0.53.1",
3
+ "version": "0.55.0",
4
4
  "description": "Low-level utilities (helper functions, etc.) used by Code PushUp CLI",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/code-pushup/cli/tree/main/packages/utils#readme",
@@ -26,7 +26,7 @@
26
26
  "main": "./index.js",
27
27
  "types": "./src/index.d.ts",
28
28
  "dependencies": {
29
- "@code-pushup/models": "0.53.1",
29
+ "@code-pushup/models": "0.55.0",
30
30
  "@isaacs/cliui": "^8.0.2",
31
31
  "@poppinss/cliui": "^6.4.0",
32
32
  "ansis": "^3.3.0",
package/src/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { exists } from '@code-pushup/models';
2
2
  export { comparePairs, matchArrayItemsByKey, type Diff } from './lib/diff';
3
3
  export { stringifyError } from './lib/errors';
4
4
  export { ProcessError, executeProcess, type ProcessConfig, type ProcessObserver, type ProcessResult, } from './lib/execute-process';
5
- export { crawlFileSystem, directoryExists, ensureDirectoryExists, fileExists, filePathToCliArg, findLineNumberInText, importModule, logMultipleFileResults, pluginWorkDir, projectToFilename, readJsonFile, readTextFile, removeDirectoryIfExists, type CrawlFileSystemOptions, type FileResult, type MultipleFileResults, } from './lib/file-system';
5
+ export { crawlFileSystem, directoryExists, ensureDirectoryExists, fileExists, filePathToCliArg, findLineNumberInText, findNearestFile, importModule, logMultipleFileResults, pluginWorkDir, projectToFilename, readJsonFile, readTextFile, removeDirectoryIfExists, type CrawlFileSystemOptions, type FileResult, type MultipleFileResults, } from './lib/file-system';
6
6
  export { filterItemRefsBy } from './lib/filter';
7
7
  export { formatBytes, formatDuration, pluralize, pluralizeToken, slugify, truncateDescription, truncateIssueMessage, truncateText, truncateTitle, } from './lib/formatting';
8
8
  export { formatGitPath, getGitRoot, guardAgainstLocalChanges, safeCheckout, toGitPath, } from './lib/git/git';
@@ -16,6 +16,7 @@ export type CrawlFileSystemOptions<T> = {
16
16
  fileTransform?: (filePath: string) => Promise<T> | T;
17
17
  };
18
18
  export declare function crawlFileSystem<T = string>(options: CrawlFileSystemOptions<T>): Promise<T[]>;
19
+ export declare function findNearestFile(fileNames: string[], cwd?: string): Promise<string | undefined>;
19
20
  export declare function findLineNumberInText(content: string, pattern: string): number | null;
20
21
  export declare function filePathToCliArg(path: string): string;
21
22
  export declare function projectToFilename(project: string): string;
@@ -1,8 +1,8 @@
1
1
  import { type InlineText, MarkdownDocument } from 'build-md';
2
2
  import type { AuditReport } from '@code-pushup/models';
3
3
  import type { ScoredGroup, ScoredReport } from './types';
4
- export declare function categoriesOverviewSection(report: Pick<ScoredReport, 'categories' | 'plugins'>): MarkdownDocument;
5
- export declare function categoriesDetailsSection(report: Pick<ScoredReport, 'categories' | 'plugins'>): MarkdownDocument;
4
+ export declare function categoriesOverviewSection(report: Required<Pick<ScoredReport, 'plugins' | 'categories'>>): MarkdownDocument;
5
+ export declare function categoriesDetailsSection(report: Required<Pick<ScoredReport, 'plugins' | 'categories'>>): MarkdownDocument;
6
6
  export declare function categoryRef({ title, score, value, displayValue }: AuditReport, pluginTitle: string): InlineText;
7
7
  export declare function categoryGroupItem({ score, title }: ScoredGroup, groupAudits: AuditReport[], pluginTitle: string): InlineText;
8
8
  export declare function binaryIconSuffix(score: number, isBinary: boolean | undefined): string;
@@ -1,5 +1,5 @@
1
1
  import type { ScoredReport } from './types';
2
2
  export declare function logStdoutSummary(report: ScoredReport, verbose?: boolean): void;
3
3
  export declare function logPlugins(plugins: ScoredReport['plugins'], verbose: boolean): void;
4
- export declare function logCategories({ categories, plugins }: ScoredReport): void;
4
+ export declare function logCategories({ plugins, categories, }: Required<Pick<ScoredReport, 'plugins' | 'categories'>>): void;
5
5
  export declare function binaryIconPrefix(score: number, isBinary: boolean | undefined): string;
@@ -9,7 +9,7 @@ export type ScoredReport = Omit<Report, 'plugins' | 'categories'> & {
9
9
  plugins: (Omit<PluginReport, 'groups'> & {
10
10
  groups?: ScoredGroup[];
11
11
  })[];
12
- categories: ScoredCategoryConfig[];
12
+ categories?: ScoredCategoryConfig[];
13
13
  };
14
14
  export type SortableGroup = ScoredGroup & {
15
15
  weight: number;
@@ -3,7 +3,6 @@ export declare function objectToKeys<T extends object>(obj: T): (keyof T)[];
3
3
  export declare function objectToEntries<T extends object>(obj: T): [keyof T, T[keyof T]][];
4
4
  export declare function objectFromEntries<K extends PropertyKey, V>(entries: [K, V][]): Record<K, V>;
5
5
  export declare function countOccurrences<T extends PropertyKey>(values: T[]): Partial<Record<T, number>>;
6
- export declare function exists<T>(value: T): value is NonNullable<T>;
7
6
  export declare function distinct<T extends string | number | boolean>(array: T[]): T[];
8
7
  export declare function deepClone<T>(obj: T): T;
9
8
  export declare function factorOf<T>(items: T[], filterFn: (i: T) => boolean): number;