@code-pushup/create-cli 0.113.0 → 0.114.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/README.md CHANGED
@@ -4,29 +4,40 @@
4
4
  [![downloads](https://img.shields.io/npm/dm/%40code-pushup%2Fcreate-cli)](https://npmtrends.com/@code-pushup/create-cli)
5
5
  [![dependencies](https://img.shields.io/librariesio/release/npm/%40code-pushup/create-cli)](https://www.npmjs.com/package/@code-pushup/create-cli?activeTab=dependencies)
6
6
 
7
- A CLI tool to set up Code PushUp in your repository.
7
+ An interactive setup wizard that scaffolds a `code-pushup.config.ts` file in your repository.
8
8
 
9
9
  ## Usage
10
10
 
11
- To set up Code PushUp, run the following command:
12
-
13
11
  ```bash
14
- npx init @code-pushup/cli
12
+ npm init @code-pushup/cli
15
13
  ```
16
14
 
17
- alternatives:
15
+ The wizard will prompt you to select plugins and configure their options, then generate a `code-pushup.config.ts` file.
16
+
17
+ ## Options
18
+
19
+ | Flag | Description | Default |
20
+ | ------------- | -------------------------------------- | ------- |
21
+ | `--plugins` | Comma-separated plugin slugs to enable | |
22
+ | `--dry-run` | Preview changes without writing files | `false` |
23
+ | `--yes`, `-y` | Skip prompts and use defaults | `false` |
24
+
25
+ ### Examples
26
+
27
+ Run interactively (default):
18
28
 
19
29
  ```bash
20
- npx @code-pushup/create-cli
21
- npm exec @code-pushup/create-cli
30
+ npm init @code-pushup/cli
22
31
  ```
23
32
 
24
- It should generate the following output:
33
+ Skip prompts and enable specific plugins:
25
34
 
26
35
  ```bash
27
- > <✓> Generating @code-pushup/nx-plugin:init
36
+ npm init @code-pushup/cli -y --plugins=eslint,coverage
37
+ ```
28
38
 
29
- > <✓> Generating @code-pushup/nx-plugin:configuration
39
+ Preview the generated config without writing:
30
40
 
31
- CREATE code-pushup.config.ts
41
+ ```bash
42
+ npm init @code-pushup/cli -y --dry-run
32
43
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-pushup/create-cli",
3
- "version": "0.113.0",
3
+ "version": "0.114.0",
4
4
  "license": "MIT",
5
5
  "bin": "index.js",
6
6
  "homepage": "https://github.com/code-pushup/cli/tree/main/packages/create-cli#readme",
@@ -26,8 +26,10 @@
26
26
  },
27
27
  "type": "module",
28
28
  "dependencies": {
29
- "@code-pushup/nx-plugin": "0.113.0",
30
- "@code-pushup/utils": "0.113.0"
29
+ "@code-pushup/models": "0.114.0",
30
+ "@code-pushup/utils": "0.114.0",
31
+ "@inquirer/prompts": "^8.0.0",
32
+ "yargs": "^17.7.2"
31
33
  },
32
34
  "files": [
33
35
  "src",
package/src/index.js CHANGED
@@ -1,4 +1,20 @@
1
1
  #! /usr/bin/env node
2
- import { initCodePushup } from './lib/init.js';
3
- await initCodePushup();
2
+ import yargs from 'yargs';
3
+ import { hideBin } from 'yargs/helpers';
4
+ import { runSetupWizard } from './lib/setup/wizard.js';
5
+ const argv = await yargs(hideBin(process.argv))
6
+ .option('dry-run', {
7
+ type: 'boolean',
8
+ default: false,
9
+ describe: 'Preview changes without writing files',
10
+ })
11
+ .option('yes', {
12
+ alias: 'y',
13
+ type: 'boolean',
14
+ default: false,
15
+ describe: 'Skip prompts and use defaults',
16
+ })
17
+ .parse();
18
+ // TODO: #1244 — provide plugin bindings from registry
19
+ await runSetupWizard([], argv);
4
20
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KAC5C,MAAM,CAAC,SAAS,EAAE;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,uCAAuC;CAClD,CAAC;KACD,MAAM,CAAC,KAAK,EAAE;IACb,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,+BAA+B;CAC1C,CAAC;KACD,KAAK,EAAE,CAAC;AAEX,sDAAsD;AACtD,MAAM,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { PluginCodegenResult } from './types.js';
2
+ export declare function generateConfigSource(plugins: PluginCodegenResult[]): string;
@@ -0,0 +1,52 @@
1
+ const CORE_CONFIG_IMPORT = {
2
+ moduleSpecifier: '@code-pushup/models',
3
+ namedImports: ['CoreConfig'],
4
+ isTypeOnly: true,
5
+ };
6
+ class CodeBuilder {
7
+ lines = [];
8
+ addLine(text, depth = 0) {
9
+ this.lines.push(`${' '.repeat(depth)}${text}`);
10
+ }
11
+ addLines(texts, depth = 0) {
12
+ texts.forEach(text => {
13
+ this.addLine(text, depth);
14
+ });
15
+ }
16
+ addEmptyLine() {
17
+ this.lines.push('');
18
+ }
19
+ toString() {
20
+ return `${this.lines.join('\n')}\n`;
21
+ }
22
+ }
23
+ function formatImport({ moduleSpecifier, defaultImport, namedImports, isTypeOnly, }) {
24
+ const named = namedImports?.length ? `{ ${namedImports.join(', ')} }` : '';
25
+ const bindings = [defaultImport, named].filter(Boolean).join(', ');
26
+ const from = bindings ? `${bindings} from ` : '';
27
+ const type = isTypeOnly ? 'type ' : '';
28
+ return `import ${type}${from}'${moduleSpecifier}';`;
29
+ }
30
+ function collectImports(plugins) {
31
+ return [
32
+ CORE_CONFIG_IMPORT,
33
+ ...plugins.flatMap(({ imports }) => imports),
34
+ ].toSorted((a, b) => a.moduleSpecifier.localeCompare(b.moduleSpecifier));
35
+ }
36
+ export function generateConfigSource(plugins) {
37
+ const builder = new CodeBuilder();
38
+ builder.addLines(collectImports(plugins).map(formatImport));
39
+ builder.addEmptyLine();
40
+ builder.addLine('export default {');
41
+ if (plugins.length === 0) {
42
+ builder.addLine('plugins: [],', 1);
43
+ }
44
+ else {
45
+ builder.addLine('plugins: [', 1);
46
+ builder.addLines(plugins.map(({ pluginInit }) => `${pluginInit},`), 2);
47
+ builder.addLine('],', 1);
48
+ }
49
+ builder.addLine('} satisfies CoreConfig;');
50
+ return builder.toString();
51
+ }
52
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../../../src/lib/setup/codegen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { CliArgs, PluginPromptDescriptor } from './types.js';
2
+ export declare function promptPluginOptions(descriptors: PluginPromptDescriptor[], cliArgs: CliArgs): Promise<Record<string, string | string[]>>;
@@ -0,0 +1,37 @@
1
+ import { checkbox, input, select } from '@inquirer/prompts';
2
+ import { asyncSequential } from '@code-pushup/utils';
3
+ // TODO: #1244 — add promptPluginSelection (multi-select prompt with pre-selection callbacks)
4
+ export async function promptPluginOptions(descriptors, cliArgs) {
5
+ const fallback = cliArgs['yes']
6
+ ? (descriptor) => descriptor.default
7
+ : runPrompt;
8
+ const entries = await asyncSequential(descriptors, async (descriptor) => [
9
+ descriptor.key,
10
+ cliValue(descriptor.key, cliArgs) ?? (await fallback(descriptor)),
11
+ ]);
12
+ return Object.fromEntries(entries);
13
+ }
14
+ function cliValue(key, cliArgs) {
15
+ const value = cliArgs[key];
16
+ return typeof value === 'string' ? value : undefined;
17
+ }
18
+ async function runPrompt(descriptor) {
19
+ switch (descriptor.type) {
20
+ case 'input':
21
+ return input({
22
+ message: descriptor.message,
23
+ default: descriptor.default,
24
+ });
25
+ case 'select':
26
+ return select({
27
+ message: descriptor.message,
28
+ choices: [...descriptor.choices],
29
+ });
30
+ case 'checkbox':
31
+ return checkbox({
32
+ message: descriptor.message,
33
+ choices: [...descriptor.choices],
34
+ });
35
+ }
36
+ }
37
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../../src/lib/setup/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,6FAA6F;AAE7F,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAqC,EACrC,OAAgB;IAEhB,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7B,CAAC,CAAC,CAAC,UAAkC,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO;QAC5D,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,KAAK,EAAC,UAAU,EAAC,EAAE,CAAC;QACrE,UAAU,CAAC,GAAG;QACd,QAAQ,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;KAClE,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,OAAgB;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,UAAkC;IAElC,QAAQ,UAAU,CAAC,IAAI,EAAE,CAAC;QACxB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC;gBACX,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,OAAO,EAAE,UAAU,CAAC,OAAO;aAC5B,CAAC,CAAC;QACL,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC;gBACZ,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,OAAO,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;aACjC,CAAC,CAAC;QACL,KAAK,UAAU;YACb,OAAO,QAAQ,CAAC;gBACd,OAAO,EAAE,UAAU,CAAC,OAAO;gBAC3B,OAAO,EAAE,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;aACjC,CAAC,CAAC;IACP,CAAC;AACH,CAAC"}
@@ -0,0 +1,70 @@
1
+ import type { PluginMeta } from '@code-pushup/models';
2
+ /** Virtual file system that buffers writes in memory until flushed to disk. */
3
+ export type Tree = {
4
+ root: string;
5
+ exists: (filePath: string) => Promise<boolean>;
6
+ read: (filePath: string) => Promise<string | null>;
7
+ write: (filePath: string, content: string) => Promise<void>;
8
+ listChanges: () => FileChange[];
9
+ flush: () => Promise<void>;
10
+ };
11
+ export type FileChange = {
12
+ path: string;
13
+ type: 'CREATE' | 'UPDATE';
14
+ content: string;
15
+ };
16
+ export type FileSystemAdapter = {
17
+ readFile: (path: string, encoding: 'utf8') => Promise<string>;
18
+ writeFile: (path: string, content: string) => Promise<void>;
19
+ exists: (path: string) => Promise<boolean>;
20
+ mkdir: (path: string, options: {
21
+ recursive: true;
22
+ }) => Promise<string | undefined>;
23
+ };
24
+ export type PluginSetupBinding = {
25
+ slug: PluginMeta['slug'];
26
+ title: PluginMeta['title'];
27
+ packageName: NonNullable<PluginMeta['packageName']>;
28
+ prompts?: PluginPromptDescriptor[];
29
+ generateConfig: (answers: Record<string, string | string[]>) => PluginCodegenResult;
30
+ };
31
+ export type ImportDeclarationStructure = {
32
+ moduleSpecifier: string;
33
+ defaultImport?: string;
34
+ namedImports?: string[];
35
+ isTypeOnly?: boolean;
36
+ };
37
+ export type PluginCodegenResult = {
38
+ imports: ImportDeclarationStructure[];
39
+ pluginInit: string;
40
+ };
41
+ type PromptBase = {
42
+ key: string;
43
+ message: string;
44
+ };
45
+ type PromptChoice<T extends string> = {
46
+ name: string;
47
+ value: T;
48
+ };
49
+ type InputPrompt = PromptBase & {
50
+ type: 'input';
51
+ default: string;
52
+ };
53
+ type SelectPrompt<T extends string = string> = PromptBase & {
54
+ type: 'select';
55
+ choices: PromptChoice<T>[];
56
+ default: T;
57
+ };
58
+ type CheckboxPrompt<T extends string = string> = PromptBase & {
59
+ type: 'checkbox';
60
+ choices: PromptChoice<T>[];
61
+ default: T[];
62
+ };
63
+ export type PluginPromptDescriptor = InputPrompt | SelectPrompt | CheckboxPrompt;
64
+ export type CliArgs = {
65
+ 'dry-run'?: boolean;
66
+ yes?: boolean;
67
+ 'target-dir'?: string;
68
+ [key: string]: unknown;
69
+ };
70
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/setup/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import type { FileSystemAdapter, Tree } from './types.js';
2
+ export declare function createTree(root: string, fs?: FileSystemAdapter): Tree;
@@ -0,0 +1,46 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileExists } from '@code-pushup/utils';
4
+ const DEFAULT_FS = {
5
+ readFile,
6
+ writeFile,
7
+ exists: fileExists,
8
+ mkdir,
9
+ };
10
+ export function createTree(root, fs = DEFAULT_FS) {
11
+ const pending = new Map();
12
+ const resolve = (filePath) => path.resolve(root, filePath);
13
+ return {
14
+ root,
15
+ exists: async (filePath) => pending.has(filePath) || fs.exists(resolve(filePath)),
16
+ read: async (filePath) => {
17
+ const entry = pending.get(filePath);
18
+ if (entry) {
19
+ return entry.content;
20
+ }
21
+ const absolutePath = resolve(filePath);
22
+ if (!(await fs.exists(absolutePath))) {
23
+ return null;
24
+ }
25
+ return fs.readFile(absolutePath, 'utf8');
26
+ },
27
+ write: async (filePath, content) => {
28
+ const type = (await fs.exists(resolve(filePath))) ? 'UPDATE' : 'CREATE';
29
+ pending.set(filePath, { content, type });
30
+ },
31
+ listChanges: () => [...pending.entries()].map(([filePath, { content, type }]) => ({
32
+ path: filePath,
33
+ type,
34
+ content,
35
+ })),
36
+ async flush() {
37
+ await Promise.all([...pending.entries()].map(async ([filePath, { content }]) => {
38
+ const absolutePath = resolve(filePath);
39
+ await fs.mkdir(path.dirname(absolutePath), { recursive: true });
40
+ await fs.writeFile(absolutePath, content);
41
+ }));
42
+ pending.clear();
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=virtual-fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-fs.js","sourceRoot":"","sources":["../../../../src/lib/setup/virtual-fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGhD,MAAM,UAAU,GAAsB;IACpC,QAAQ;IACR,SAAS;IACT,MAAM,EAAE,UAAU;IAClB,KAAK;CACN,CAAC;AAEF,MAAM,UAAU,UAAU,CACxB,IAAY,EACZ,KAAwB,UAAU;IAElC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgD,CAAC;IAExE,MAAM,OAAO,GAAG,CAAC,QAAgB,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAE3E,OAAO;QACL,IAAI;QAEJ,MAAM,EAAE,KAAK,EAAE,QAAgB,EAAoB,EAAE,CACnD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEvD,IAAI,EAAE,KAAK,EAAE,QAAgB,EAA0B,EAAE;YACvD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC,OAAO,CAAC;YACvB,CAAC;YACD,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;QAED,KAAK,EAAE,KAAK,EAAE,QAAgB,EAAE,OAAe,EAAiB,EAAE;YAChE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAED,WAAW,EAAE,GAAiB,EAAE,CAC9B,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7D,IAAI,EAAE,QAAQ;YACd,IAAI;YACJ,OAAO;SACR,CAAC,CAAC;QAEL,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,GAAG,CACf,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE;gBAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACvC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChE,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YAC5C,CAAC,CAAC,CACH,CAAC;YACF,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { CliArgs, PluginSetupBinding } from './types.js';
2
+ export declare function runSetupWizard(bindings: PluginSetupBinding[], cliArgs: CliArgs): Promise<void>;
@@ -0,0 +1,46 @@
1
+ import { asyncSequential, formatAsciiTable, logger } from '@code-pushup/utils';
2
+ import { generateConfigSource } from './codegen.js';
3
+ import { promptPluginOptions } from './prompts.js';
4
+ import { createTree } from './virtual-fs.js';
5
+ export async function runSetupWizard(bindings, cliArgs) {
6
+ const targetDir = cliArgs['target-dir'] ?? process.cwd();
7
+ // TODO: #1245 — prompt for standalone vs monorepo mode
8
+ // TODO: #1244 — prompt user to select plugins from available bindings
9
+ const pluginResults = await asyncSequential(bindings, binding => resolveBinding(binding, cliArgs));
10
+ const tree = createTree(targetDir);
11
+ // TODO: #1243 — select config file format (TS/JS/MJS) based on user choice or tsconfig detection
12
+ await tree.write('code-pushup.config.ts', generateConfigSource(pluginResults));
13
+ const changes = tree.listChanges();
14
+ if (cliArgs['dry-run']) {
15
+ logChanges(changes);
16
+ logger.info('Dry run — no files written.');
17
+ }
18
+ else {
19
+ await tree.flush();
20
+ logChanges(changes);
21
+ logger.info('Setup complete.');
22
+ logger.newline();
23
+ logNextSteps([
24
+ ['npx code-pushup', 'Collect your first report'],
25
+ ['https://github.com/code-pushup/cli#readme', 'Documentation'],
26
+ ]);
27
+ }
28
+ }
29
+ async function resolveBinding(binding, cliArgs) {
30
+ const answers = binding.prompts
31
+ ? await promptPluginOptions(binding.prompts, cliArgs)
32
+ : {};
33
+ return binding.generateConfig(answers);
34
+ }
35
+ function logChanges(changes) {
36
+ changes.forEach(change => {
37
+ logger.info(`${change.type} ${change.path}`);
38
+ });
39
+ }
40
+ function logNextSteps(steps) {
41
+ logger.info(formatAsciiTable({
42
+ title: 'Next steps:',
43
+ rows: steps,
44
+ }, { borderless: true }));
45
+ }
46
+ //# sourceMappingURL=wizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../../../src/lib/setup/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAOnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAA8B,EAC9B,OAAgB;IAEhB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEzD,uDAAuD;IACvD,sEAAsE;IAEtE,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAC9D,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CACjC,CAAC;IAEF,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACnC,iGAAiG;IACjG,MAAM,IAAI,CAAC,KAAK,CACd,uBAAuB,EACvB,oBAAoB,CAAC,aAAa,CAAC,CACpC,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEnC,IAAI,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACvB,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,UAAU,CAAC,OAAO,CAAC,CAAC;QACpB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC/B,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,YAAY,CAAC;YACX,CAAC,iBAAiB,EAAE,2BAA2B,CAAC;YAChD,CAAC,2CAA2C,EAAE,eAAe,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,OAA2B,EAC3B,OAAgB;IAEhB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;QAC7B,CAAC,CAAC,MAAM,mBAAmB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC;QACrD,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CAAC,OAAqB;IACvC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QACvB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,MAAM,CAAC,IAAI,CACT,gBAAgB,CACd;QACE,KAAK,EAAE,aAAa;QACpB,IAAI,EAAE,KAAK;KACZ,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,CACrB,CACF,CAAC;AACJ,CAAC"}
@@ -1,5 +0,0 @@
1
- export declare const NX_JSON_FILENAME = "nx.json";
2
- export declare const NX_JSON_CONTENT: string;
3
- export declare const PROJECT_NAME = "source-root";
4
- export declare const PROJECT_JSON_FILENAME = "project.json";
5
- export declare const PROJECT_JSON_CONTENT: string;
@@ -1,12 +0,0 @@
1
- export const NX_JSON_FILENAME = 'nx.json';
2
- export const NX_JSON_CONTENT = JSON.stringify({
3
- $schema: './node_modules/nx/schemas/nx-schema.json',
4
- targetDefaults: {},
5
- });
6
- export const PROJECT_NAME = 'source-root';
7
- export const PROJECT_JSON_FILENAME = 'project.json';
8
- export const PROJECT_JSON_CONTENT = JSON.stringify({
9
- $schema: 'node_modules/nx/schemas/project-schema.json',
10
- name: PROJECT_NAME,
11
- });
12
- //# sourceMappingURL=constants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC;IAC5C,OAAO,EAAE,0CAA0C;IACnD,cAAc,EAAE,EAAE;CACnB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,aAAa,CAAC;AAC1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;AACpD,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,SAAS,CAAC;IACjD,OAAO,EAAE,6CAA6C;IACtD,IAAI,EAAE,YAAY;CACnB,CAAC,CAAC"}
package/src/lib/init.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import { type ProcessConfig } from '@code-pushup/utils';
2
- export declare function nxPluginGenerator(generator: 'init' | 'configuration', opt?: Record<string, unknown>): ProcessConfig;
3
- export declare function initCodePushup(): Promise<void>;
package/src/lib/init.js DELETED
@@ -1,27 +0,0 @@
1
- import { executeProcess, objectToCliArgs, } from '@code-pushup/utils';
2
- import { parseNxProcessOutput, setupNxContext, teardownNxContext, } from './utils.js';
3
- export function nxPluginGenerator(generator, opt = {}) {
4
- return {
5
- command: 'npx',
6
- args: objectToCliArgs({
7
- _: ['nx', 'g', `@code-pushup/nx-plugin:${generator}`],
8
- ...opt,
9
- }),
10
- };
11
- }
12
- export async function initCodePushup() {
13
- const setupResult = await setupNxContext();
14
- await executeProcess({
15
- ...nxPluginGenerator('init', {
16
- skipNxJson: true,
17
- }),
18
- });
19
- const { stdout: configStdout, stderr: configStderr } = await executeProcess(nxPluginGenerator('configuration', {
20
- skipTarget: true,
21
- project: setupResult.projectName,
22
- }));
23
- console.info(parseNxProcessOutput(configStdout));
24
- console.warn(parseNxProcessOutput(configStderr));
25
- await teardownNxContext(setupResult);
26
- }
27
- //# sourceMappingURL=init.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/lib/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,MAAM,UAAU,iBAAiB,CAC/B,SAAmC,EACnC,MAA+B,EAAE;IAEjC,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,eAAe,CAAC;YACpB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,0BAA0B,SAAS,EAAE,CAAC;YACrD,GAAG,GAAG;SACP,CAAC;KACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAE3C,MAAM,cAAc,CAAC;QACnB,GAAG,iBAAiB,CAAC,MAAM,EAAE;YAC3B,UAAU,EAAE,IAAI;SACjB,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,cAAc,CACzE,iBAAiB,CAAC,eAAe,EAAE;QACjC,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,WAAW,CAAC,WAAW;KACjC,CAAC,CACH,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,YAAY,CAAC,CAAC,CAAC;IAEjD,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACvC,CAAC"}
@@ -1,15 +0,0 @@
1
- export type SetupResult = {
2
- filename: string;
3
- teardown: boolean;
4
- };
5
- export declare function setupFile(filename: string, content?: string): Promise<SetupResult>;
6
- export declare function parseNxProcessOutput(output: string): string;
7
- export declare function setupNxContext(): Promise<{
8
- nxJsonTeardown: boolean;
9
- projectJsonTeardown: boolean;
10
- projectName: string;
11
- }>;
12
- export declare function teardownNxContext({ nxJsonTeardown, projectJsonTeardown, }: {
13
- nxJsonTeardown: boolean;
14
- projectJsonTeardown: boolean;
15
- }): Promise<void>;
package/src/lib/utils.js DELETED
@@ -1,51 +0,0 @@
1
- import { readFile, rm, stat, writeFile } from 'node:fs/promises';
2
- import { CODE_PUSHUP_UNICODE_LOGO } from '@code-pushup/utils';
3
- import { NX_JSON_CONTENT, NX_JSON_FILENAME, PROJECT_JSON_CONTENT, PROJECT_JSON_FILENAME, PROJECT_NAME, } from './constants.js';
4
- export async function setupFile(filename, content = '') {
5
- const setupResult = {
6
- filename,
7
- teardown: false,
8
- };
9
- try {
10
- const stats = await stat(filename);
11
- if (!stats.isFile()) {
12
- await writeFile(filename, content);
13
- }
14
- }
15
- catch (error) {
16
- if (error instanceof Error &&
17
- error.message.includes('no such file or directory')) {
18
- await writeFile(filename, content);
19
- return {
20
- ...setupResult,
21
- teardown: true,
22
- };
23
- }
24
- else {
25
- console.error(error);
26
- }
27
- }
28
- return setupResult;
29
- }
30
- export function parseNxProcessOutput(output) {
31
- return output.trim().replace('NX', CODE_PUSHUP_UNICODE_LOGO);
32
- }
33
- export async function setupNxContext() {
34
- const { teardown: nxJsonTeardown } = await setupFile(NX_JSON_FILENAME, NX_JSON_CONTENT);
35
- const { teardown: projectJsonTeardown } = await setupFile(PROJECT_JSON_FILENAME, PROJECT_JSON_CONTENT);
36
- const projectJsonContent = await readFile(PROJECT_JSON_FILENAME, 'utf8');
37
- const { name = PROJECT_NAME } = JSON.parse(projectJsonContent);
38
- return {
39
- nxJsonTeardown,
40
- projectJsonTeardown,
41
- projectName: name,
42
- };
43
- }
44
- export async function teardownNxContext({ nxJsonTeardown, projectJsonTeardown, }) {
45
- const filesToDelete = [
46
- ...(nxJsonTeardown ? [NX_JSON_FILENAME] : []),
47
- ...(projectJsonTeardown ? [PROJECT_JSON_FILENAME] : []),
48
- ];
49
- await Promise.all(filesToDelete.map(file => rm(file)));
50
- }
51
- //# sourceMappingURL=utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAOxB,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,QAAgB,EAChB,OAAO,GAAG,EAAE;IAEZ,MAAM,WAAW,GAAgB;QAC/B,QAAQ;QACR,QAAQ,EAAE,KAAK;KAChB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACpB,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,KAAK,YAAY,KAAK;YACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EACnD,CAAC;YACD,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACnC,OAAO;gBACL,GAAG,WAAW;gBACd,QAAQ,EAAE,IAAI;aACf,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,wBAAwB,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAKlC,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,SAAS,CAClD,gBAAgB,EAChB,eAAe,CAChB,CAAC;IACF,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,GAAG,MAAM,SAAS,CACvD,qBAAqB,EACrB,oBAAoB,CACrB,CAAC;IAEF,MAAM,kBAAkB,GAAG,MAAM,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IACzE,MAAM,EAAE,IAAI,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAE5D,CAAC;IAEF,OAAO;QACL,cAAc;QACd,mBAAmB;QACnB,WAAW,EAAE,IAAI;KAClB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EACtC,cAAc,EACd,mBAAmB,GAIpB;IACC,MAAM,aAAa,GAAG;QACpB,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACxD,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACzD,CAAC"}