@pagopa/dx-cli 0.4.1 → 0.4.3

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 +124 -35
  2. package/package.json +5 -2
package/bin/index.js CHANGED
@@ -167,6 +167,40 @@ var checkTurboConfig = async (dependencies, config2) => {
167
167
  });
168
168
  };
169
169
 
170
+ // src/domain/workspace.ts
171
+ import { ok as ok3 } from "neverthrow";
172
+ import { z as z2 } from "zod/v4";
173
+ var WorkspaceName = z2.string().min(1).brand();
174
+ var workspaceSchema = z2.object({
175
+ name: WorkspaceName,
176
+ path: z2.string()
177
+ });
178
+ var checkWorkspaces = async (dependencies, monorepoDir) => {
179
+ const { repositoryReader: repositoryReader2 } = dependencies;
180
+ const checkName = "Workspaces";
181
+ const workspacesResult = await repositoryReader2.getWorkspaces(monorepoDir);
182
+ if (workspacesResult.isErr()) {
183
+ return ok3({
184
+ checkName,
185
+ errorMessage: "Something is wrong with the workspaces configuration. If you need help, please contact the DevEx team.",
186
+ isValid: false
187
+ });
188
+ }
189
+ const { length: workspaceNumber } = workspacesResult.value;
190
+ if (workspaceNumber === 0) {
191
+ return ok3({
192
+ checkName,
193
+ errorMessage: "No workspace configuration found. Make sure to configure workspaces in pnpm-workspace.yaml.",
194
+ isValid: false
195
+ });
196
+ }
197
+ return ok3({
198
+ checkName,
199
+ isValid: true,
200
+ successMessage: `Found ${workspaceNumber} workspace${workspaceNumber === 1 ? "" : "s"}`
201
+ });
202
+ };
203
+
170
204
  // src/domain/doctor.ts
171
205
  var runDoctor = (dependencies, config2) => {
172
206
  const doctorChecks = [
@@ -181,6 +215,10 @@ var runDoctor = (dependencies, config2) => {
181
215
  ResultAsync3.fromPromise(
182
216
  checkMonorepoScripts(dependencies, config2),
183
217
  () => new Error("Error checking monorepo scripts")
218
+ ),
219
+ ResultAsync3.fromPromise(
220
+ checkWorkspaces(dependencies, config2.repository.root),
221
+ () => new Error("Error checking monorepo scripts")
184
222
  )
185
223
  ];
186
224
  return ResultAsync3.combine(doctorChecks).match(
@@ -247,8 +285,9 @@ var detectPackageManager = async (dependencies, config2) => {
247
285
  const packageManager = dependencies.packageJson.packageManager ?? await detectFromLockFile(dependencies, config2);
248
286
  return packageManager ?? "npm";
249
287
  };
250
- var detectNodeVersion = async ({ repositoryReader: repositoryReader2 }, nodeVersionFilePath) => await repositoryReader2.readFile(nodeVersionFilePath).unwrapOr(void 0);
288
+ var detectNodeVersion = async ({ repositoryReader: repositoryReader2 }, nodeVersionFilePath) => await repositoryReader2.readFile(nodeVersionFilePath).map((nodeVersion) => nodeVersion.trim()).unwrapOr(void 0);
251
289
  var detectTerraformVersion = async ({ repositoryReader: repositoryReader2 }, terraformVersionFilePath) => await repositoryReader2.readFile(terraformVersionFilePath).map((tfVersion) => tfVersion.trim()).unwrapOr(void 0);
290
+ var detectTurboVersion = ({ devDependencies }) => devDependencies.get("turbo")?.trim();
252
291
  var getInfo = async (dependencies, config2) => ({
253
292
  node: await detectNodeVersion(
254
293
  { repositoryReader: dependencies.repositoryReader },
@@ -256,9 +295,10 @@ var getInfo = async (dependencies, config2) => ({
256
295
  ),
257
296
  packageManager: await detectPackageManager(dependencies, config2),
258
297
  terraform: await detectTerraformVersion(
259
- dependencies,
298
+ { repositoryReader: dependencies.repositoryReader },
260
299
  `${config2.repository.root}/.terraform-version`
261
- )
300
+ ),
301
+ turbo: detectTurboVersion(dependencies.packageJson)
262
302
  });
263
303
  var printInfo = (result) => {
264
304
  const logger2 = getLogger("json");
@@ -278,7 +318,7 @@ import { Command as Command3 } from "commander";
278
318
  import { getLogger as getLogger2 } from "@logtape/logtape";
279
319
  function printVersion() {
280
320
  const logger2 = getLogger2(["dx-cli", "version"]);
281
- logger2.info(`dx CLI version: ${"0.4.1"}`);
321
+ logger2.info(`dx CLI version: ${"0.4.3"}`);
282
322
  }
283
323
 
284
324
  // src/adapters/commander/commands/version.ts
@@ -287,7 +327,7 @@ var makeVersionCommand = () => new Command3().name("version").alias("v").action(
287
327
  // src/adapters/commander/index.ts
288
328
  var makeCli = (deps2, config2) => {
289
329
  const program2 = new Command4();
290
- program2.name("dx").description("The CLI for DX-Platform").version("0.4.1");
330
+ program2.name("dx").description("The CLI for DX-Platform").version("0.4.3");
291
331
  program2.addCommand(makeDoctorCommand(deps2, config2));
292
332
  program2.addCommand(makeVersionCommand());
293
333
  program2.addCommand(makeInfoCommand(deps2, config2));
@@ -305,18 +345,6 @@ var makeValidationReporter = () => {
305
345
  } else {
306
346
  logger2.error(`\u274C ${result.errorMessage}`);
307
347
  }
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
348
  }
321
349
  };
322
350
  };
@@ -326,26 +354,32 @@ import { join as join2 } from "path";
326
354
  import * as process3 from "process";
327
355
 
328
356
  // src/adapters/node/fs/file-reader.ts
329
- import { Result, ResultAsync as ResultAsync4 } from "neverthrow";
357
+ import { ResultAsync as ResultAsync5 } from "neverthrow";
330
358
  import fs2 from "fs/promises";
331
- var readFile = (filePath) => ResultAsync4.fromPromise(
359
+
360
+ // src/adapters/zod/index.ts
361
+ import { ResultAsync as ResultAsync4 } from "neverthrow";
362
+ var decode = (schema) => ResultAsync4.fromThrowable(
363
+ schema.parseAsync,
364
+ (cause) => new Error("File content is not valid for the given schema", { cause })
365
+ );
366
+
367
+ // src/adapters/node/json/index.ts
368
+ import { Result } from "neverthrow";
369
+ var parseJson = Result.fromThrowable(
370
+ JSON.parse,
371
+ (cause) => new Error("Failed to parse JSON", { cause })
372
+ );
373
+
374
+ // src/adapters/node/fs/file-reader.ts
375
+ var readFile = (filePath) => ResultAsync5.fromPromise(
332
376
  fs2.readFile(filePath, "utf-8"),
333
377
  (cause) => new Error(`Failed to read file: ${filePath}`, { cause })
334
378
  );
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.`)
379
+ var readFileAndDecode = (filePath, schema) => readFile(filePath).andThen(parseJson).andThen(decode(schema));
380
+ var fileExists = (path2) => ResultAsync5.fromPromise(
381
+ fs2.stat(path2),
382
+ () => new Error(`${path2} not found.`)
349
383
  ).map(() => true);
350
384
 
351
385
  // src/adapters/node/package-json.ts
@@ -373,18 +407,73 @@ var makePackageJsonReader = () => ({
373
407
  });
374
408
 
375
409
  // src/adapters/node/repository.ts
376
- import { join as join3 } from "path";
410
+ import * as glob from "glob";
411
+ import { okAsync, ResultAsync as ResultAsync6 } from "neverthrow";
412
+ import * as path from "path";
413
+ import { z as z3 } from "zod/v4";
414
+
415
+ // src/adapters/yaml/index.ts
416
+ import { Result as Result2 } from "neverthrow";
417
+ import yaml from "yaml";
418
+ var parseYaml = Result2.fromThrowable(
419
+ (content) => yaml.parse(content),
420
+ () => new Error("Failed to parse YAML")
421
+ );
422
+
423
+ // src/adapters/node/repository.ts
377
424
  var findRepositoryRoot = (dir = process.cwd()) => {
378
- const gitPath = join3(dir, ".git");
425
+ const gitPath = path.join(dir, ".git");
379
426
  return fileExists(gitPath).mapErr(
380
427
  () => new Error(
381
428
  "Could not find repository root. Make sure to have the repo initialized."
382
429
  )
383
430
  ).map(() => dir);
384
431
  };
432
+ var resolveWorkspacePattern = (repoRoot2, pattern) => ResultAsync6.fromPromise(
433
+ // For now it is not possible to use the fs.glob function (from node:fs/promises)
434
+ // because it is not possible to run it on Node 20.x
435
+ glob.glob(pattern, { cwd: repoRoot2 }),
436
+ (cause) => new Error(`Failed to resolve workspace glob: ${pattern}`, {
437
+ cause
438
+ })
439
+ ).map(
440
+ (subDirectories) => (
441
+ // Create the absolute path to the subdirectory
442
+ subDirectories.map((directory) => path.join(repoRoot2, directory))
443
+ )
444
+ );
445
+ var getWorkspaces = (repoRoot2) => readFile(path.join(repoRoot2, "pnpm-workspace.yaml")).andThen(parseYaml).andThen(
446
+ (obj) => (
447
+ // If no packages are defined, go on with an empty array
448
+ decode(z3.object({ packages: z3.array(z3.string()) }))(obj).orElse(
449
+ () => okAsync({ packages: [] })
450
+ )
451
+ )
452
+ ).andThen(
453
+ ({ packages }) => (
454
+ // For every package pattern in the pnpm-workspace.yaml file, get the list of subdirectories
455
+ ResultAsync6.combine(
456
+ packages.map((pattern) => resolveWorkspacePattern(repoRoot2, pattern))
457
+ ).map((workspacesList) => workspacesList.flat()).andThen((workspaceFolders) => {
458
+ const workspaceResults = workspaceFolders.map(
459
+ (nodeWorkspaceDirectory) => readFileAndDecode(
460
+ path.join(nodeWorkspaceDirectory, "package.json"),
461
+ packageJsonSchema
462
+ ).map(
463
+ ({ name }) => (
464
+ // Create the workspace object using the package.json name and the nodeWorkspaceDirectory
465
+ workspaceSchema.parse({ name, path: nodeWorkspaceDirectory })
466
+ )
467
+ )
468
+ );
469
+ return ResultAsync6.combine(workspaceResults);
470
+ })
471
+ )
472
+ );
385
473
  var makeRepositoryReader = () => ({
386
474
  fileExists,
387
475
  findRepositoryRoot,
476
+ getWorkspaces,
388
477
  readFile
389
478
  });
390
479
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/dx-cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
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": {
@@ -31,7 +33,8 @@
31
33
  "@types/node": "^22.16.2",
32
34
  "@types/semver": "^7.7.0",
33
35
  "@vitest/coverage-v8": "^3.2.4",
34
- "eslint": "^9.31.0",
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",