@pagopa/dx-cli 0.4.2 → 0.4.4

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 +125 -40
  2. package/package.json +4 -1
package/bin/index.js CHANGED
@@ -22,9 +22,8 @@ var scriptSchema = z.object({
22
22
  name: ScriptName,
23
23
  script: z.string()
24
24
  });
25
- var DependencyName = z.string().brand();
26
25
  var dependencySchema = z.object({
27
- name: DependencyName,
26
+ name: z.string(),
28
27
  version: z.string()
29
28
  });
30
29
  var PackageName = z.string().min(1).brand();
@@ -36,12 +35,9 @@ var scriptsSchema = z.record(ScriptName, z.string()).optional().transform(
36
35
  ]) : []
37
36
  )
38
37
  );
39
- var dependenciesSchema = z.record(DependencyName, z.string()).optional().transform(
38
+ var dependenciesSchema = z.record(z.string(), z.string()).optional().transform(
40
39
  (obj) => new Map(
41
- obj ? Object.entries(obj).map(([name, version]) => [
42
- DependencyName.parse(name),
43
- version
44
- ]) : []
40
+ obj ? Object.entries(obj).map(([name, version]) => [name, version]) : []
45
41
  )
46
42
  );
47
43
  var packageManagerSchema = z.enum(["npm", "pnpm", "yarn"]);
@@ -167,6 +163,40 @@ var checkTurboConfig = async (dependencies, config2) => {
167
163
  });
168
164
  };
169
165
 
166
+ // src/domain/workspace.ts
167
+ import { ok as ok3 } from "neverthrow";
168
+ import { z as z2 } from "zod/v4";
169
+ var WorkspaceName = z2.string().min(1).brand();
170
+ var workspaceSchema = z2.object({
171
+ name: WorkspaceName,
172
+ path: z2.string()
173
+ });
174
+ var checkWorkspaces = async (dependencies, monorepoDir) => {
175
+ const { repositoryReader: repositoryReader2 } = dependencies;
176
+ const checkName = "Workspaces";
177
+ const workspacesResult = await repositoryReader2.getWorkspaces(monorepoDir);
178
+ if (workspacesResult.isErr()) {
179
+ return ok3({
180
+ checkName,
181
+ errorMessage: "Something is wrong with the workspaces configuration. If you need help, please contact the DevEx team.",
182
+ isValid: false
183
+ });
184
+ }
185
+ const { length: workspaceNumber } = workspacesResult.value;
186
+ if (workspaceNumber === 0) {
187
+ return ok3({
188
+ checkName,
189
+ errorMessage: "No workspace configuration found. Make sure to configure workspaces in pnpm-workspace.yaml.",
190
+ isValid: false
191
+ });
192
+ }
193
+ return ok3({
194
+ checkName,
195
+ isValid: true,
196
+ successMessage: `Found ${workspaceNumber} workspace${workspaceNumber === 1 ? "" : "s"}`
197
+ });
198
+ };
199
+
170
200
  // src/domain/doctor.ts
171
201
  var runDoctor = (dependencies, config2) => {
172
202
  const doctorChecks = [
@@ -181,6 +211,10 @@ var runDoctor = (dependencies, config2) => {
181
211
  ResultAsync3.fromPromise(
182
212
  checkMonorepoScripts(dependencies, config2),
183
213
  () => new Error("Error checking monorepo scripts")
214
+ ),
215
+ ResultAsync3.fromPromise(
216
+ checkWorkspaces(dependencies, config2.repository.root),
217
+ () => new Error("Error checking monorepo scripts")
184
218
  )
185
219
  ];
186
220
  return ResultAsync3.combine(doctorChecks).match(
@@ -249,6 +283,7 @@ var detectPackageManager = async (dependencies, config2) => {
249
283
  };
250
284
  var detectNodeVersion = async ({ repositoryReader: repositoryReader2 }, nodeVersionFilePath) => await repositoryReader2.readFile(nodeVersionFilePath).map((nodeVersion) => nodeVersion.trim()).unwrapOr(void 0);
251
285
  var detectTerraformVersion = async ({ repositoryReader: repositoryReader2 }, terraformVersionFilePath) => await repositoryReader2.readFile(terraformVersionFilePath).map((tfVersion) => tfVersion.trim()).unwrapOr(void 0);
286
+ var detectTurboVersion = ({ devDependencies }) => devDependencies.get("turbo")?.trim();
252
287
  var getInfo = async (dependencies, config2) => ({
253
288
  node: await detectNodeVersion(
254
289
  { repositoryReader: dependencies.repositoryReader },
@@ -258,7 +293,8 @@ var getInfo = async (dependencies, config2) => ({
258
293
  terraform: await detectTerraformVersion(
259
294
  { repositoryReader: dependencies.repositoryReader },
260
295
  `${config2.repository.root}/.terraform-version`
261
- )
296
+ ),
297
+ turbo: detectTurboVersion(dependencies.packageJson)
262
298
  });
263
299
  var printInfo = (result) => {
264
300
  const logger2 = getLogger("json");
@@ -278,7 +314,7 @@ import { Command as Command3 } from "commander";
278
314
  import { getLogger as getLogger2 } from "@logtape/logtape";
279
315
  function printVersion() {
280
316
  const logger2 = getLogger2(["dx-cli", "version"]);
281
- logger2.info(`dx CLI version: ${"0.4.2"}`);
317
+ logger2.info(`dx CLI version: ${"0.4.4"}`);
282
318
  }
283
319
 
284
320
  // src/adapters/commander/commands/version.ts
@@ -287,7 +323,7 @@ var makeVersionCommand = () => new Command3().name("version").alias("v").action(
287
323
  // src/adapters/commander/index.ts
288
324
  var makeCli = (deps2, config2) => {
289
325
  const program2 = new Command4();
290
- program2.name("dx").description("The CLI for DX-Platform").version("0.4.2");
326
+ program2.name("dx").description("The CLI for DX-Platform").version("0.4.4");
291
327
  program2.addCommand(makeDoctorCommand(deps2, config2));
292
328
  program2.addCommand(makeVersionCommand());
293
329
  program2.addCommand(makeInfoCommand(deps2, config2));
@@ -305,18 +341,6 @@ var makeValidationReporter = () => {
305
341
  } else {
306
342
  logger2.error(`\u274C ${result.errorMessage}`);
307
343
  }
308
- },
309
- reportValidationResult(result) {
310
- if (result.isOk()) {
311
- const validation = result.value;
312
- if (validation.isValid) {
313
- logger2.info(`\u2705 ${validation.successMessage}`);
314
- } else {
315
- logger2.error(`\u274C ${validation.errorMessage}`);
316
- }
317
- } else {
318
- logger2.error(`\u274C ${result.error.message}`);
319
- }
320
344
  }
321
345
  };
322
346
  };
@@ -326,26 +350,32 @@ import { join as join2 } from "path";
326
350
  import * as process3 from "process";
327
351
 
328
352
  // src/adapters/node/fs/file-reader.ts
329
- import { Result, ResultAsync as ResultAsync4 } from "neverthrow";
353
+ import { ResultAsync as ResultAsync5 } from "neverthrow";
330
354
  import fs2 from "fs/promises";
331
- var readFile = (filePath) => ResultAsync4.fromPromise(
355
+
356
+ // src/adapters/zod/index.ts
357
+ import { ResultAsync as ResultAsync4 } from "neverthrow";
358
+ var decode = (schema) => ResultAsync4.fromThrowable(
359
+ schema.parseAsync,
360
+ (cause) => new Error("File content is not valid for the given schema", { cause })
361
+ );
362
+
363
+ // src/adapters/node/json/index.ts
364
+ import { Result } from "neverthrow";
365
+ var parseJson = Result.fromThrowable(
366
+ JSON.parse,
367
+ (cause) => new Error("Failed to parse JSON", { cause })
368
+ );
369
+
370
+ // src/adapters/node/fs/file-reader.ts
371
+ var readFile = (filePath) => ResultAsync5.fromPromise(
332
372
  fs2.readFile(filePath, "utf-8"),
333
373
  (cause) => new Error(`Failed to read file: ${filePath}`, { cause })
334
374
  );
335
- var readFileAndDecode = (filePath, schema) => {
336
- const decode = ResultAsync4.fromThrowable(
337
- schema.parseAsync,
338
- () => new Error("File content is not valid for the given schema")
339
- );
340
- const toJSON = Result.fromThrowable(
341
- JSON.parse,
342
- () => new Error("Failed to parse JSON")
343
- );
344
- return readFile(filePath).andThen(toJSON).andThen(decode);
345
- };
346
- var fileExists = (path) => ResultAsync4.fromPromise(
347
- fs2.stat(path),
348
- () => new Error(`${path} not found.`)
375
+ var readFileAndDecode = (filePath, schema) => readFile(filePath).andThen(parseJson).andThen(decode(schema));
376
+ var fileExists = (path2) => ResultAsync5.fromPromise(
377
+ fs2.stat(path2),
378
+ () => new Error(`${path2} not found.`)
349
379
  ).map(() => true);
350
380
 
351
381
  // src/adapters/node/package-json.ts
@@ -373,18 +403,73 @@ var makePackageJsonReader = () => ({
373
403
  });
374
404
 
375
405
  // src/adapters/node/repository.ts
376
- import { join as join3 } from "path";
406
+ import * as glob from "glob";
407
+ import { okAsync, ResultAsync as ResultAsync6 } from "neverthrow";
408
+ import * as path from "path";
409
+ import { z as z3 } from "zod/v4";
410
+
411
+ // src/adapters/yaml/index.ts
412
+ import { Result as Result2 } from "neverthrow";
413
+ import yaml from "yaml";
414
+ var parseYaml = Result2.fromThrowable(
415
+ (content) => yaml.parse(content),
416
+ () => new Error("Failed to parse YAML")
417
+ );
418
+
419
+ // src/adapters/node/repository.ts
377
420
  var findRepositoryRoot = (dir = process.cwd()) => {
378
- const gitPath = join3(dir, ".git");
421
+ const gitPath = path.join(dir, ".git");
379
422
  return fileExists(gitPath).mapErr(
380
423
  () => new Error(
381
424
  "Could not find repository root. Make sure to have the repo initialized."
382
425
  )
383
426
  ).map(() => dir);
384
427
  };
428
+ var resolveWorkspacePattern = (repoRoot2, pattern) => ResultAsync6.fromPromise(
429
+ // For now it is not possible to use the fs.glob function (from node:fs/promises)
430
+ // because it is not possible to run it on Node 20.x
431
+ glob.glob(pattern, { cwd: repoRoot2 }),
432
+ (cause) => new Error(`Failed to resolve workspace glob: ${pattern}`, {
433
+ cause
434
+ })
435
+ ).map(
436
+ (subDirectories) => (
437
+ // Create the absolute path to the subdirectory
438
+ subDirectories.map((directory) => path.join(repoRoot2, directory))
439
+ )
440
+ );
441
+ var getWorkspaces = (repoRoot2) => readFile(path.join(repoRoot2, "pnpm-workspace.yaml")).andThen(parseYaml).andThen(
442
+ (obj) => (
443
+ // If no packages are defined, go on with an empty array
444
+ decode(z3.object({ packages: z3.array(z3.string()) }))(obj).orElse(
445
+ () => okAsync({ packages: [] })
446
+ )
447
+ )
448
+ ).andThen(
449
+ ({ packages }) => (
450
+ // For every package pattern in the pnpm-workspace.yaml file, get the list of subdirectories
451
+ ResultAsync6.combine(
452
+ packages.map((pattern) => resolveWorkspacePattern(repoRoot2, pattern))
453
+ ).map((workspacesList) => workspacesList.flat()).andThen((workspaceFolders) => {
454
+ const workspaceResults = workspaceFolders.map(
455
+ (nodeWorkspaceDirectory) => readFileAndDecode(
456
+ path.join(nodeWorkspaceDirectory, "package.json"),
457
+ packageJsonSchema
458
+ ).map(
459
+ ({ name }) => (
460
+ // Create the workspace object using the package.json name and the nodeWorkspaceDirectory
461
+ workspaceSchema.parse({ name, path: nodeWorkspaceDirectory })
462
+ )
463
+ )
464
+ );
465
+ return ResultAsync6.combine(workspaceResults);
466
+ })
467
+ )
468
+ );
385
469
  var makeRepositoryReader = () => ({
386
470
  fileExists,
387
471
  findRepositoryRoot,
472
+ getWorkspaces,
388
473
  readFile
389
474
  });
390
475
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "description": "A CLI useful to manage DX tools.",
6
6
  "repository": {
@@ -22,8 +22,10 @@
22
22
  "@logtape/logtape": "^1.0.0",
23
23
  "commander": "^14.0.0",
24
24
  "core-js": "^3.44.0",
25
+ "glob": "^11.0.3",
25
26
  "neverthrow": "^8.2.0",
26
27
  "semver": "^7.7.2",
28
+ "yaml": "^2.8.0",
27
29
  "zod": "^3.25.28"
28
30
  },
29
31
  "devDependencies": {
@@ -32,6 +34,7 @@
32
34
  "@types/semver": "^7.7.0",
33
35
  "@vitest/coverage-v8": "^3.2.4",
34
36
  "eslint": "^9.30.0",
37
+ "memfs": "^4.23.0",
35
38
  "prettier": "3.6.2",
36
39
  "tsup": "^8.5.0",
37
40
  "typescript": "~5.8.3",