@pagopa/dx-cli 0.4.4 → 0.6.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.
Files changed (2) hide show
  1. package/bin/index.js +132 -24
  2. package/package.json +7 -5
package/bin/index.js CHANGED
@@ -4,11 +4,68 @@
4
4
  import "core-js/actual/set/index.js";
5
5
  import { configure, getConsoleSink, getLogger as getLogger4 } from "@logtape/logtape";
6
6
 
7
+ // src/adapters/codemods/example.ts
8
+ import { okAsync } from "neverthrow";
9
+ var apply = () => {
10
+ console.log("Hello from example codemod!");
11
+ return okAsync(void 0);
12
+ };
13
+ var example_default = {
14
+ apply,
15
+ description: "An example codemod that does nothing",
16
+ id: "example"
17
+ };
18
+
19
+ // src/adapters/codemods/registry.ts
20
+ import { okAsync as okAsync2 } from "neverthrow";
21
+ var LocalCodemodRegistry = class {
22
+ #m;
23
+ constructor() {
24
+ this.#m = /* @__PURE__ */ new Map();
25
+ }
26
+ add(codemod) {
27
+ this.#m.set(codemod.id, codemod);
28
+ }
29
+ getAll() {
30
+ return okAsync2(Array.from(this.#m.values()));
31
+ }
32
+ getById(id) {
33
+ return okAsync2(this.#m.get(id));
34
+ }
35
+ };
36
+
37
+ // src/adapters/codemods/index.ts
38
+ var registry = new LocalCodemodRegistry();
39
+ registry.add(example_default);
40
+ var codemods_default = registry;
41
+
7
42
  // src/adapters/commander/index.ts
8
- import { Command as Command4 } from "commander";
43
+ import { Command as Command6 } from "commander";
9
44
 
10
- // src/adapters/commander/commands/doctor.ts
45
+ // src/adapters/commander/commands/codemod.ts
11
46
  import { Command } from "commander";
47
+ var makeCodemodCommand = ({
48
+ applyCodemodById: applyCodemodById2,
49
+ listCodemods: listCodemods2
50
+ }) => new Command("codemod").description("Manage and apply migration scripts to the repository").addCommand(
51
+ new Command("list").description("List available migration scripts").action(async function() {
52
+ await listCodemods2().andTee(
53
+ (codemods) => (
54
+ // eslint-disable-next-line no-console
55
+ console.table(codemods, ["id", "description"])
56
+ )
57
+ ).orTee((error) => this.error(error.message));
58
+ })
59
+ ).addCommand(
60
+ new Command("apply").argument("<id>", "The id of the codemod to apply").description("Apply migration scripts to the repository").action(async function(id) {
61
+ await applyCodemodById2(id).andTee(() => {
62
+ console.log("Codemod applied successfully \u2705");
63
+ }).orTee((error) => this.error(error.message));
64
+ })
65
+ );
66
+
67
+ // src/adapters/commander/commands/doctor.ts
68
+ import { Command as Command2 } from "commander";
12
69
  import * as process2 from "process";
13
70
 
14
71
  // src/domain/doctor.ts
@@ -245,7 +302,7 @@ var toDoctorResult = (validationCheckResults) => {
245
302
  var printDoctorResult = ({ validationReporter: validationReporter2 }, result) => result.checks.map(validationReporter2.reportCheckResult);
246
303
 
247
304
  // src/adapters/commander/commands/doctor.ts
248
- var makeDoctorCommand = (dependencies, config2) => new Command().name("doctor").description(
305
+ var makeDoctorCommand = (dependencies, config2) => new Command2().name("doctor").description(
249
306
  "Verify the repository setup according to the DevEx guidelines"
250
307
  ).action(async () => {
251
308
  const result = await runDoctor(dependencies, config2);
@@ -255,7 +312,7 @@ var makeDoctorCommand = (dependencies, config2) => new Command().name("doctor").
255
312
  });
256
313
 
257
314
  // src/adapters/commander/commands/info.ts
258
- import { Command as Command2 } from "commander";
315
+ import { Command as Command3 } from "commander";
259
316
 
260
317
  // src/domain/info.ts
261
318
  import { getLogger } from "@logtape/logtape";
@@ -302,29 +359,69 @@ var printInfo = (result) => {
302
359
  };
303
360
 
304
361
  // src/adapters/commander/commands/info.ts
305
- var makeInfoCommand = (dependencies, config2) => new Command2().name("info").description("Display information about the project").action(async () => {
362
+ var makeInfoCommand = (dependencies, config2) => new Command3().name("info").description("Display information about the project").action(async () => {
306
363
  const result = await getInfo(dependencies, config2);
307
364
  printInfo(result);
308
365
  });
309
366
 
367
+ // src/adapters/commander/commands/init.ts
368
+ import scaffoldMonorepo from "@pagopa/monorepo-generator";
369
+ import { Command as Command4 } from "commander";
370
+ import { Result, ResultAsync as ResultAsync4 } from "neverthrow";
371
+ import nodePlop from "node-plop";
372
+ var initPlop = () => ResultAsync4.fromPromise(
373
+ nodePlop(),
374
+ () => new Error("Failed to initialize plop")
375
+ );
376
+ var getGenerator = (plopAPI) => Result.fromThrowable(
377
+ plopAPI.getGenerator,
378
+ () => new Error("Generator not found")
379
+ );
380
+ var runGenerator = (generator) => ResultAsync4.fromPromise(
381
+ generator.runPrompts(),
382
+ () => new Error("Failed to run the generator prompts")
383
+ ).andThen(
384
+ (answers) => ResultAsync4.fromPromise(
385
+ generator.runActions(answers),
386
+ () => new Error("Failed to run the generator actions")
387
+ )
388
+ );
389
+ var makeInitCommand = () => new Command4().name("init").description(
390
+ "Command to initialize resources (like projects, subscriptions, ...)"
391
+ ).addCommand(
392
+ new Command4("project").description("Initialize a new monorepo project").action(async function() {
393
+ await initPlop().andTee(scaffoldMonorepo).andThen((plop) => getGenerator(plop)("monorepo")).andThen(runGenerator).andTee(() => {
394
+ console.log("Monorepo initialized successfully \u2705");
395
+ }).orTee((err2) => {
396
+ this.error(err2.message);
397
+ });
398
+ })
399
+ );
400
+
310
401
  // src/adapters/commander/commands/version.ts
311
- import { Command as Command3 } from "commander";
402
+ import { Command as Command5 } from "commander";
312
403
 
313
404
  // src/domain/version.ts
314
405
  import { getLogger as getLogger2 } from "@logtape/logtape";
315
406
  function printVersion() {
316
407
  const logger2 = getLogger2(["dx-cli", "version"]);
317
- logger2.info(`dx CLI version: ${"0.4.4"}`);
408
+ logger2.info(`dx CLI version: ${"0.6.0"}`);
318
409
  }
319
410
 
320
411
  // src/adapters/commander/commands/version.ts
321
- var makeVersionCommand = () => new Command3().name("version").alias("v").action(() => printVersion());
412
+ var makeVersionCommand = () => new Command5().name("version").alias("v").action(() => printVersion());
322
413
 
323
414
  // src/adapters/commander/index.ts
324
415
  var makeCli = (deps2, config2) => {
325
- const program2 = new Command4();
326
- program2.name("dx").description("The CLI for DX-Platform").version("0.4.4");
416
+ const program2 = new Command6();
417
+ program2.name("dx").description("The CLI for DX-Platform").version("0.6.0");
327
418
  program2.addCommand(makeDoctorCommand(deps2, config2));
419
+ if (process.env.ENABLE_CODEMODS) {
420
+ program2.addCommand(makeCodemodCommand(deps2));
421
+ }
422
+ if (process.env.ENABLE_INIT_COMMAND) {
423
+ program2.addCommand(makeInitCommand());
424
+ }
328
425
  program2.addCommand(makeVersionCommand());
329
426
  program2.addCommand(makeInfoCommand(deps2, config2));
330
427
  return program2;
@@ -350,30 +447,30 @@ import { join as join2 } from "path";
350
447
  import * as process3 from "process";
351
448
 
352
449
  // src/adapters/node/fs/file-reader.ts
353
- import { ResultAsync as ResultAsync5 } from "neverthrow";
450
+ import { ResultAsync as ResultAsync6 } from "neverthrow";
354
451
  import fs2 from "fs/promises";
355
452
 
356
453
  // src/adapters/zod/index.ts
357
- import { ResultAsync as ResultAsync4 } from "neverthrow";
358
- var decode = (schema) => ResultAsync4.fromThrowable(
454
+ import { ResultAsync as ResultAsync5 } from "neverthrow";
455
+ var decode = (schema) => ResultAsync5.fromThrowable(
359
456
  schema.parseAsync,
360
457
  (cause) => new Error("File content is not valid for the given schema", { cause })
361
458
  );
362
459
 
363
460
  // src/adapters/node/json/index.ts
364
- import { Result } from "neverthrow";
365
- var parseJson = Result.fromThrowable(
461
+ import { Result as Result2 } from "neverthrow";
462
+ var parseJson = Result2.fromThrowable(
366
463
  JSON.parse,
367
464
  (cause) => new Error("Failed to parse JSON", { cause })
368
465
  );
369
466
 
370
467
  // src/adapters/node/fs/file-reader.ts
371
- var readFile = (filePath) => ResultAsync5.fromPromise(
468
+ var readFile = (filePath) => ResultAsync6.fromPromise(
372
469
  fs2.readFile(filePath, "utf-8"),
373
470
  (cause) => new Error(`Failed to read file: ${filePath}`, { cause })
374
471
  );
375
472
  var readFileAndDecode = (filePath, schema) => readFile(filePath).andThen(parseJson).andThen(decode(schema));
376
- var fileExists = (path2) => ResultAsync5.fromPromise(
473
+ var fileExists = (path2) => ResultAsync6.fromPromise(
377
474
  fs2.stat(path2),
378
475
  () => new Error(`${path2} not found.`)
379
476
  ).map(() => true);
@@ -404,14 +501,14 @@ var makePackageJsonReader = () => ({
404
501
 
405
502
  // src/adapters/node/repository.ts
406
503
  import * as glob from "glob";
407
- import { okAsync, ResultAsync as ResultAsync6 } from "neverthrow";
504
+ import { okAsync as okAsync3, ResultAsync as ResultAsync7 } from "neverthrow";
408
505
  import * as path from "path";
409
506
  import { z as z3 } from "zod/v4";
410
507
 
411
508
  // src/adapters/yaml/index.ts
412
- import { Result as Result2 } from "neverthrow";
509
+ import { Result as Result3 } from "neverthrow";
413
510
  import yaml from "yaml";
414
- var parseYaml = Result2.fromThrowable(
511
+ var parseYaml = Result3.fromThrowable(
415
512
  (content) => yaml.parse(content),
416
513
  () => new Error("Failed to parse YAML")
417
514
  );
@@ -425,7 +522,7 @@ var findRepositoryRoot = (dir = process.cwd()) => {
425
522
  )
426
523
  ).map(() => dir);
427
524
  };
428
- var resolveWorkspacePattern = (repoRoot2, pattern) => ResultAsync6.fromPromise(
525
+ var resolveWorkspacePattern = (repoRoot2, pattern) => ResultAsync7.fromPromise(
429
526
  // For now it is not possible to use the fs.glob function (from node:fs/promises)
430
527
  // because it is not possible to run it on Node 20.x
431
528
  glob.glob(pattern, { cwd: repoRoot2 }),
@@ -442,13 +539,13 @@ var getWorkspaces = (repoRoot2) => readFile(path.join(repoRoot2, "pnpm-workspace
442
539
  (obj) => (
443
540
  // If no packages are defined, go on with an empty array
444
541
  decode(z3.object({ packages: z3.array(z3.string()) }))(obj).orElse(
445
- () => okAsync({ packages: [] })
542
+ () => okAsync3({ packages: [] })
446
543
  )
447
544
  )
448
545
  ).andThen(
449
546
  ({ packages }) => (
450
547
  // For every package pattern in the pnpm-workspace.yaml file, get the list of subdirectories
451
- ResultAsync6.combine(
548
+ ResultAsync7.combine(
452
549
  packages.map((pattern) => resolveWorkspacePattern(repoRoot2, pattern))
453
550
  ).map((workspacesList) => workspacesList.flat()).andThen((workspaceFolders) => {
454
551
  const workspaceResults = workspaceFolders.map(
@@ -462,7 +559,7 @@ var getWorkspaces = (repoRoot2) => readFile(path.join(repoRoot2, "pnpm-workspace
462
559
  )
463
560
  )
464
561
  );
465
- return ResultAsync6.combine(workspaceResults);
562
+ return ResultAsync7.combine(workspaceResults);
466
563
  })
467
564
  )
468
565
  );
@@ -483,6 +580,15 @@ var getConfig = (repositoryRoot2) => ({
483
580
  }
484
581
  });
485
582
 
583
+ // src/use-cases/apply-codemod.ts
584
+ import { errAsync, okAsync as okAsync4 } from "neverthrow";
585
+ var applyCodemodById = (registry2) => (id) => registry2.getById(id).andThen(
586
+ (codemod) => codemod ? okAsync4(codemod) : errAsync(new Error(`Codemod with id ${id} not found`))
587
+ ).andThen((codemod) => codemod.apply());
588
+
589
+ // src/use-cases/list-codemods.ts
590
+ var listCodemods = (registry2) => () => registry2.getAll();
591
+
486
592
  // src/index.ts
487
593
  await configure({
488
594
  loggers: [
@@ -520,6 +626,8 @@ if (repoPackageJson.isErr()) {
520
626
  }
521
627
  var packageJson = repoPackageJson.value;
522
628
  var deps = {
629
+ applyCodemodById: applyCodemodById(codemods_default),
630
+ listCodemods: listCodemods(codemods_default),
523
631
  packageJson,
524
632
  packageJsonReader,
525
633
  repositoryReader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.4.4",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -24,14 +24,16 @@
24
24
  "core-js": "^3.44.0",
25
25
  "glob": "^11.0.3",
26
26
  "neverthrow": "^8.2.0",
27
+ "node-plop": "^0.32.1",
27
28
  "semver": "^7.7.2",
28
29
  "yaml": "^2.8.0",
29
- "zod": "^3.25.28"
30
+ "zod": "^3.25.28",
31
+ "@pagopa/monorepo-generator": "^0.6.0"
30
32
  },
31
33
  "devDependencies": {
32
34
  "@tsconfig/node22": "22.0.2",
33
35
  "@types/node": "^22.16.2",
34
- "@types/semver": "^7.7.0",
36
+ "@types/semver": "^7.7.1",
35
37
  "@vitest/coverage-v8": "^3.2.4",
36
38
  "eslint": "^9.30.0",
37
39
  "memfs": "^4.23.0",
@@ -40,7 +42,7 @@
40
42
  "typescript": "~5.8.3",
41
43
  "vitest": "^3.2.4",
42
44
  "vitest-mock-extended": "^3.1.0",
43
- "@pagopa/eslint-config": "^5.0.0"
45
+ "@pagopa/eslint-config": "^5.1.0"
44
46
  },
45
47
  "engines": {
46
48
  "node": ">=22.0.0"
@@ -53,6 +55,6 @@
53
55
  "format:check": "prettier --check .",
54
56
  "typecheck": "tsc --noEmit",
55
57
  "test": "vitest run",
56
- "test:coverage": "vitest --coverage"
58
+ "test:coverage": "vitest run --coverage"
57
59
  }
58
60
  }