@mnci/cli 1.9.1 → 1.11.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/dist/cli.js CHANGED
@@ -38,11 +38,32 @@ module.exports = __toCommonJS(cli_exports);
38
38
  var import_commander = require("commander");
39
39
 
40
40
  // src/commands/add.ts
41
- var import_node_path8 = require("path");
41
+ var import_node_path9 = require("path");
42
42
  var import_prompts4 = require("@inquirer/prompts");
43
43
 
44
44
  // src/nx.ts
45
45
  var import_cross_spawn = __toESM(require("cross-spawn"));
46
+
47
+ // src/util/logger.ts
48
+ var logger = {
49
+ info(message) {
50
+ console.log(message);
51
+ },
52
+ step(message) {
53
+ console.log(`\u2192 ${message}`);
54
+ },
55
+ success(message) {
56
+ console.log(`\u2713 ${message}`);
57
+ },
58
+ warn(message) {
59
+ console.warn(`! ${message}`);
60
+ },
61
+ error(message) {
62
+ console.error(`\u2717 ${message}`);
63
+ }
64
+ };
65
+
66
+ // src/nx.ts
46
67
  function runShell(command, arguments_, cwd) {
47
68
  const result = import_cross_spawn.default.sync(command, arguments_, { stdio: "inherit", cwd });
48
69
  return result.status ?? 1;
@@ -59,6 +80,14 @@ function runNpx(arguments_, cwd) {
59
80
  throw new Error(`npx ${arguments_.join(" ")} failed with exit code ${status}`);
60
81
  }
61
82
  }
83
+ function runPrettier(cwd, target = ".") {
84
+ const status = runShell("npx", ["prettier", "--write", "--log-level", "warn", target], cwd);
85
+ if (status !== 0) {
86
+ logger.warn(
87
+ `Prettier could not format '${target}' (exit code ${status}). The project was generated; run 'npm run format' to normalise it.`
88
+ );
89
+ }
90
+ }
62
91
 
63
92
  // src/prompts.ts
64
93
  var import_prompts = require("@inquirer/prompts");
@@ -136,25 +165,6 @@ function fileExists(path) {
136
165
  return (0, import_node_fs.existsSync)(path);
137
166
  }
138
167
 
139
- // src/util/logger.ts
140
- var logger = {
141
- info(message) {
142
- console.log(message);
143
- },
144
- step(message) {
145
- console.log(`\u2192 ${message}`);
146
- },
147
- success(message) {
148
- console.log(`\u2713 ${message}`);
149
- },
150
- warn(message) {
151
- console.warn(`! ${message}`);
152
- },
153
- error(message) {
154
- console.error(`\u2717 ${message}`);
155
- }
156
- };
157
-
158
168
  // src/util/names.ts
159
169
  function assertValidProjectName(name, label) {
160
170
  if (!/^[a-z][a-z0-9-]*$/.test(name)) {
@@ -164,7 +174,11 @@ function assertValidProjectName(name, label) {
164
174
  }
165
175
  }
166
176
 
177
+ // src/commands/add/flutter.ts
178
+ var import_node_path3 = require("path");
179
+
167
180
  // src/commands/add/shared.ts
181
+ var import_node_fs2 = require("fs");
168
182
  var import_node_path2 = require("path");
169
183
  function hasPlugin(workspaceRoot, packageName) {
170
184
  const manifest = readJson((0, import_node_path2.join)(workspaceRoot, "package.json"));
@@ -198,8 +212,93 @@ function addNxTargets(manifestPath, newTargets) {
198
212
  toJson({ ...manifest, nx: { ...nx, targets: { ...targets, ...newTargets } } })
199
213
  );
200
214
  }
215
+ var ESLINT_CONFIG_FILENAMES = [
216
+ "eslint.config.js",
217
+ "eslint.config.mjs",
218
+ "eslint.config.cjs",
219
+ "eslint.config.ts",
220
+ "eslint.config.mts",
221
+ "eslint.config.cts"
222
+ ];
223
+ function removeGeneratedEslintConfig(workspaceRoot, projectRoot) {
224
+ for (const filename of ESLINT_CONFIG_FILENAMES) {
225
+ (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, projectRoot, filename), { force: true });
226
+ }
227
+ (0, import_node_fs2.rmSync)((0, import_node_path2.join)(workspaceRoot, ".vscode"), { recursive: true, force: true });
228
+ }
229
+ function findCodeWorkspaceFile(workspaceRoot) {
230
+ try {
231
+ const entry = (0, import_node_fs2.readdirSync)(workspaceRoot).find((file) => file.endsWith(".code-workspace"));
232
+ return entry ? (0, import_node_path2.join)(workspaceRoot, entry) : void 0;
233
+ } catch {
234
+ return void 0;
235
+ }
236
+ }
237
+ function readCodeWorkspaceFile(path) {
238
+ const contents = (0, import_node_fs2.readFileSync)(path, "utf8").replaceAll(/,(\s*[}\]])/g, "$1");
239
+ return JSON.parse(contents);
240
+ }
241
+ function projectTask(name, kind) {
242
+ const script = `${name}:${kind}`;
243
+ const base = { label: `${name}: ${kind}`, type: "npm", script, problemMatcher: [] };
244
+ return kind === "start" ? { ...base, isBackground: true } : { ...base, group: kind };
245
+ }
246
+ function registerProjectCommands(workspaceRoot, name, commands) {
247
+ const scripts = {
248
+ [`${name}:qa`]: `nx run ${name}:lint && nx run ${name}:test`
249
+ };
250
+ if (commands.build) {
251
+ scripts[`${name}:build`] = `nx run ${name}:build`;
252
+ }
253
+ if (commands.start) {
254
+ scripts[`${name}:start`] = commands.start;
255
+ }
256
+ const manifestPath = (0, import_node_path2.join)(workspaceRoot, "package.json");
257
+ const manifest = readJson(manifestPath);
258
+ const existingScripts = manifest.scripts ?? {};
259
+ writeFileEnsured(
260
+ manifestPath,
261
+ toJson({ ...manifest, scripts: { ...existingScripts, ...scripts } })
262
+ );
263
+ const codeWorkspacePath = findCodeWorkspaceFile(workspaceRoot);
264
+ if (!codeWorkspacePath) {
265
+ return;
266
+ }
267
+ const workspaceFile = readCodeWorkspaceFile(codeWorkspacePath);
268
+ const label = (task) => task.label ?? "";
269
+ const existingTasks = (workspaceFile.tasks?.tasks ?? []).filter(
270
+ (task) => !label(task).startsWith(`${name}: `)
271
+ );
272
+ const newTasks = [
273
+ projectTask(name, "qa"),
274
+ ...commands.build ? [projectTask(name, "build")] : [],
275
+ ...commands.start ? [projectTask(name, "start")] : []
276
+ ];
277
+ writeFileEnsured(
278
+ codeWorkspacePath,
279
+ toJson({
280
+ ...workspaceFile,
281
+ tasks: {
282
+ version: workspaceFile.tasks?.version ?? "2.0.0",
283
+ tasks: [...existingTasks, ...newTasks]
284
+ }
285
+ })
286
+ );
287
+ }
201
288
 
202
289
  // src/commands/add/flutter.ts
290
+ function addProjectJsonTargets(projectJsonPath, newTargets) {
291
+ const project = readJson(projectJsonPath);
292
+ const targets = project.targets ?? {};
293
+ writeFileEnsured(projectJsonPath, toJson({ ...project, targets: { ...targets, ...newTargets } }));
294
+ }
295
+ function flutterAppStartTarget(name) {
296
+ return {
297
+ executor: "nx:run-commands",
298
+ continuous: true,
299
+ options: { command: "flutter run -d chrome", cwd: `apps/${name}` }
300
+ };
301
+ }
203
302
  function ensureFlutter(workspaceRoot) {
204
303
  if (runShell("flutter", ["--version"], workspaceRoot) !== 0) {
205
304
  throw new Error(
@@ -228,19 +327,25 @@ function addFlutterApp(workspaceRoot, name) {
228
327
  prepareFlutter(workspaceRoot);
229
328
  ensureAdmZip(workspaceRoot);
230
329
  runNx(["g", "@mnci/nx-flutter:application", name, "--no-interactive"], workspaceRoot);
330
+ addProjectJsonTargets((0, import_node_path3.join)(workspaceRoot, "apps", name, "project.json"), {
331
+ start: flutterAppStartTarget(name)
332
+ });
333
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
231
334
  }
232
335
  function addFlutterLib(workspaceRoot, name) {
233
336
  prepareFlutter(workspaceRoot);
234
337
  runNx(["g", "@mnci/nx-flutter:library", name, "--no-interactive"], workspaceRoot);
338
+ registerProjectCommands(workspaceRoot, name, { build: false });
235
339
  }
236
340
  function addFlutterInternalLib(workspaceRoot, name) {
237
341
  prepareFlutter(workspaceRoot);
238
342
  runNx(["g", "@mnci/nx-flutter:internal-library", name, "--no-interactive"], workspaceRoot);
343
+ registerProjectCommands(workspaceRoot, name, { build: false });
239
344
  }
240
345
 
241
346
  // src/commands/add/go.ts
242
- var import_node_fs2 = require("fs");
243
- var import_node_path3 = require("path");
347
+ var import_node_fs3 = require("fs");
348
+ var import_node_path4 = require("path");
244
349
  function ensureGo(workspaceRoot) {
245
350
  if (runShell("go", ["version"], workspaceRoot) !== 0) {
246
351
  throw new Error("Go not found. Install Go 1.21+ first: https://go.dev/dl/");
@@ -267,7 +372,7 @@ function ensureNxGoPlugin(workspaceRoot) {
267
372
  }
268
373
  }
269
374
  function ensureGoModule(workspaceRoot) {
270
- if (fileExists((0, import_node_path3.join)(workspaceRoot, "go.mod"))) {
375
+ if (fileExists((0, import_node_path4.join)(workspaceRoot, "go.mod"))) {
271
376
  return;
272
377
  }
273
378
  logger.step("Bootstrapping the workspace Go module (single root go.mod)");
@@ -276,13 +381,13 @@ function ensureGoModule(workspaceRoot) {
276
381
  }
277
382
  function goModulePath(workspaceRoot) {
278
383
  try {
279
- const contents = (0, import_node_fs2.readFileSync)((0, import_node_path3.join)(workspaceRoot, "go.mod"), "utf8");
384
+ const contents = (0, import_node_fs3.readFileSync)((0, import_node_path4.join)(workspaceRoot, "go.mod"), "utf8");
280
385
  return /^module\s+(\S+)/m.exec(contents)?.[1];
281
386
  } catch {
282
387
  return void 0;
283
388
  }
284
389
  }
285
- function addProjectJsonTargets(projectJsonPath, newTargets) {
390
+ function addProjectJsonTargets2(projectJsonPath, newTargets) {
286
391
  const project = readJson(projectJsonPath);
287
392
  const targets = project.targets ?? {};
288
393
  writeFileEnsured(projectJsonPath, toJson({ ...project, targets: { ...targets, ...newTargets } }));
@@ -296,7 +401,6 @@ function goLintTarget() {
296
401
  function goBuildTarget(name) {
297
402
  return {
298
403
  executor: "@nx-go/nx-go:build",
299
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
300
404
  outputs: [`{workspaceRoot}/dist/apps/${name}`],
301
405
  options: { outputPath: `../../dist/apps/${name}/${name}` }
302
406
  };
@@ -307,11 +411,17 @@ function goPackageTarget(tag, name) {
307
411
  return {
308
412
  executor: "nx:run-commands",
309
413
  dependsOn: ["build"],
310
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
311
414
  outputs: [`{workspaceRoot}/${zip}`],
312
415
  options: { command }
313
416
  };
314
417
  }
418
+ function goStartTarget(name) {
419
+ return {
420
+ executor: "nx:run-commands",
421
+ continuous: true,
422
+ options: { command: "go run .", cwd: `apps/${name}` }
423
+ };
424
+ }
315
425
  function prepareGo(workspaceRoot) {
316
426
  ensureGo(workspaceRoot);
317
427
  warnIfNoGolangciLint(workspaceRoot);
@@ -332,12 +442,14 @@ function addGoApp(workspaceRoot, name) {
332
442
  ],
333
443
  workspaceRoot
334
444
  );
335
- addProjectJsonTargets((0, import_node_path3.join)(workspaceRoot, "apps", name, "project.json"), {
445
+ addProjectJsonTargets2((0, import_node_path4.join)(workspaceRoot, "apps", name, "project.json"), {
336
446
  build: goBuildTarget(name),
337
447
  test: goTestTarget(),
338
448
  lint: goLintTarget(),
339
- package: goPackageTarget("go-app", name)
449
+ package: goPackageTarget("go-app", name),
450
+ start: goStartTarget(name)
340
451
  });
452
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
341
453
  }
342
454
  function addGoFunctionApp(workspaceRoot, name) {
343
455
  prepareGo(workspaceRoot);
@@ -353,12 +465,13 @@ function addGoFunctionApp(workspaceRoot, name) {
353
465
  ],
354
466
  workspaceRoot
355
467
  );
356
- addProjectJsonTargets((0, import_node_path3.join)(workspaceRoot, "apps", name, "project.json"), {
468
+ addProjectJsonTargets2((0, import_node_path4.join)(workspaceRoot, "apps", name, "project.json"), {
357
469
  build: goBuildTarget(name),
358
470
  test: goTestTarget(),
359
471
  lint: goLintTarget(),
360
472
  package: goPackageTarget("go-function-app", name)
361
473
  });
474
+ registerProjectCommands(workspaceRoot, name, { build: true });
362
475
  }
363
476
  function addGoLib(workspaceRoot, name) {
364
477
  prepareGo(workspaceRoot);
@@ -373,10 +486,11 @@ function addGoLib(workspaceRoot, name) {
373
486
  ],
374
487
  workspaceRoot
375
488
  );
376
- addProjectJsonTargets((0, import_node_path3.join)(workspaceRoot, "packages", name, "project.json"), {
489
+ addProjectJsonTargets2((0, import_node_path4.join)(workspaceRoot, "packages", name, "project.json"), {
377
490
  test: goTestTarget(),
378
491
  lint: goLintTarget()
379
492
  });
493
+ registerProjectCommands(workspaceRoot, name, { build: false });
380
494
  const module2 = goModulePath(workspaceRoot);
381
495
  if (module2) {
382
496
  logger.step(`Import it as ${module2}/packages/${name}`);
@@ -395,10 +509,11 @@ function addGoInternalLib(workspaceRoot, name) {
395
509
  ],
396
510
  workspaceRoot
397
511
  );
398
- addProjectJsonTargets((0, import_node_path3.join)(workspaceRoot, "libs", name, "project.json"), {
512
+ addProjectJsonTargets2((0, import_node_path4.join)(workspaceRoot, "libs", name, "project.json"), {
399
513
  test: goTestTarget(),
400
514
  lint: goLintTarget()
401
515
  });
516
+ registerProjectCommands(workspaceRoot, name, { build: false });
402
517
  const module2 = goModulePath(workspaceRoot);
403
518
  if (module2) {
404
519
  logger.step(`Import it as ${module2}/libs/${name}`);
@@ -406,7 +521,7 @@ function addGoInternalLib(workspaceRoot, name) {
406
521
  }
407
522
 
408
523
  // src/commands/add/node.ts
409
- var import_node_path4 = require("path");
524
+ var import_node_path5 = require("path");
410
525
  function ensurePlugin(workspaceRoot, packageName) {
411
526
  if (hasPlugin(workspaceRoot, packageName)) {
412
527
  return;
@@ -423,7 +538,7 @@ function runNodeApp(workspaceRoot, name, stack, framework) {
423
538
  `apps/${name}`,
424
539
  "--bundler=esbuild",
425
540
  `--unitTestRunner=${stack.testRunner}`,
426
- "--linter=eslint",
541
+ "--linter=none",
427
542
  "--e2eTestRunner=none",
428
543
  `--framework=${framework}`,
429
544
  "--no-interactive"
@@ -437,7 +552,6 @@ function nodeAppPackageTarget(name) {
437
552
  return {
438
553
  executor: "nx:run-commands",
439
554
  dependsOn: ["build"],
440
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
441
555
  outputs: [`{workspaceRoot}/${zip}`],
442
556
  options: { command }
443
557
  };
@@ -445,9 +559,11 @@ function nodeAppPackageTarget(name) {
445
559
  function addNodeApp(workspaceRoot, name, stack, framework = "none") {
446
560
  runNodeApp(workspaceRoot, name, stack, framework);
447
561
  ensureAdmZip(workspaceRoot);
448
- addNxTargets((0, import_node_path4.join)(workspaceRoot, "apps", name, "package.json"), {
562
+ addNxTargets((0, import_node_path5.join)(workspaceRoot, "apps", name, "package.json"), {
449
563
  package: nodeAppPackageTarget(name)
450
564
  });
565
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
566
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
451
567
  }
452
568
  function ensureAzureFunctionsPackage(workspaceRoot) {
453
569
  if (hasPlugin(workspaceRoot, "@azure/functions")) {
@@ -470,10 +586,11 @@ var NODE_FUNCTION_APP_HOST_JSON = `{
470
586
  }
471
587
  }
472
588
  `;
473
- var NODE_FUNCTION_APP_HELLO = `import { app, HttpRequest, HttpResponseInit } from '@azure/functions'
589
+ var NODE_FUNCTION_APP_HELLO = `import { app } from '@azure/functions'
590
+ import type { HttpRequest, HttpResponseInit } from '@azure/functions'
474
591
  import { buildGreeting } from './greeting'
475
592
 
476
- async function hello (request: HttpRequest): Promise<HttpResponseInit> {
593
+ async function hello(request: HttpRequest): Promise<HttpResponseInit> {
477
594
  const name = request.query.get('name') ?? 'world'
478
595
  return { body: buildGreeting(name) }
479
596
  }
@@ -498,17 +615,17 @@ describe('buildGreeting', () => {
498
615
  })
499
616
  `;
500
617
  function repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot) {
501
- const manifestPath = (0, import_node_path4.join)(nodeFunctionAppRoot, "package.json");
618
+ const manifestPath = (0, import_node_path5.join)(nodeFunctionAppRoot, "package.json");
502
619
  const manifest = readJson(manifestPath);
503
620
  const azureFunctionsVersion = readJson(
504
- (0, import_node_path4.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
621
+ (0, import_node_path5.join)(workspaceRoot, "node_modules/@azure/functions/package.json")
505
622
  ).version;
506
623
  const dependencies = manifest.dependencies ?? {};
507
624
  writeFileEnsured(
508
625
  manifestPath,
509
626
  toJson({
510
627
  ...manifest,
511
- main: "main.js",
628
+ main: "dist/main.js",
512
629
  dependencies: { ...dependencies, "@azure/functions": `^${azureFunctionsVersion}` }
513
630
  })
514
631
  );
@@ -516,90 +633,49 @@ function repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot) {
516
633
  function nodeFunctionAppPackageTarget(name) {
517
634
  const zip = `dist/drop/node-function-app-${name}.zip`;
518
635
  const root = `apps/${name}`;
519
- const command = `node -e "const fs=require('node:fs');fs.mkdirSync('dist/drop',{recursive:true});const A=require('adm-zip');const z=new A();z.addLocalFolder('${root}/dist');z.addLocalFile('${root}/host.json');z.addLocalFile('${root}/package.json');z.writeZip('${zip}')"`;
636
+ const command = `node -e "const fs=require('node:fs');fs.mkdirSync('dist/drop',{recursive:true});const A=require('adm-zip');const z=new A();z.addLocalFolder('${root}/dist','dist');z.addLocalFile('${root}/host.json');z.addLocalFile('${root}/package.json');z.writeZip('${zip}')"`;
520
637
  return {
521
638
  executor: "nx:run-commands",
522
639
  dependsOn: ["build"],
523
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
524
640
  outputs: [`{workspaceRoot}/${zip}`],
525
641
  options: { command }
526
642
  };
527
643
  }
644
+ function nodeFunctionAppStartTarget(name) {
645
+ return {
646
+ executor: "nx:run-commands",
647
+ dependsOn: ["build"],
648
+ continuous: true,
649
+ options: { command: "func start", cwd: `apps/${name}` }
650
+ };
651
+ }
528
652
  function addNodeFunctionApp(workspaceRoot, name, stack) {
529
653
  runNodeApp(workspaceRoot, name, stack, "none");
530
654
  ensureAzureFunctionsPackage(workspaceRoot);
531
- const nodeFunctionAppRoot = (0, import_node_path4.join)(workspaceRoot, "apps", name);
532
- writeFileEnsured((0, import_node_path4.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
533
- writeFileEnsured((0, import_node_path4.join)(nodeFunctionAppRoot, "src/functions/hello.ts"), NODE_FUNCTION_APP_HELLO);
655
+ const nodeFunctionAppRoot = (0, import_node_path5.join)(workspaceRoot, "apps", name);
656
+ writeFileEnsured((0, import_node_path5.join)(nodeFunctionAppRoot, "src/main.ts"), NODE_FUNCTION_APP_MAIN);
657
+ writeFileEnsured((0, import_node_path5.join)(nodeFunctionAppRoot, "src/functions/hello.ts"), NODE_FUNCTION_APP_HELLO);
534
658
  writeFileEnsured(
535
- (0, import_node_path4.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
659
+ (0, import_node_path5.join)(nodeFunctionAppRoot, "src/functions/greeting.ts"),
536
660
  NODE_FUNCTION_APP_GREETING
537
661
  );
538
662
  writeFileEnsured(
539
- (0, import_node_path4.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
663
+ (0, import_node_path5.join)(nodeFunctionAppRoot, "src/functions/greeting.spec.ts"),
540
664
  NODE_FUNCTION_APP_GREETING_SPEC
541
665
  );
542
- writeFileEnsured((0, import_node_path4.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
666
+ writeFileEnsured((0, import_node_path5.join)(nodeFunctionAppRoot, "host.json"), NODE_FUNCTION_APP_HOST_JSON);
543
667
  repairNodeFunctionAppManifest(nodeFunctionAppRoot, workspaceRoot);
544
668
  ensureAdmZip(workspaceRoot);
545
- addNxTargets((0, import_node_path4.join)(nodeFunctionAppRoot, "package.json"), {
546
- package: nodeFunctionAppPackageTarget(name)
669
+ addNxTargets((0, import_node_path5.join)(nodeFunctionAppRoot, "package.json"), {
670
+ package: nodeFunctionAppPackageTarget(name),
671
+ start: nodeFunctionAppStartTarget(name)
547
672
  });
673
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
674
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
548
675
  }
549
676
 
550
677
  // src/commands/add/npmLib.ts
551
- var import_node_path5 = require("path");
552
- var NPM_LIB_ESLINT_CONFIG = `import { globSync, readFileSync } from 'node:fs';
553
- import { dirname, join } from 'node:path';
554
- import { fileURLToPath } from 'node:url';
555
- import baseConfig from '../../eslint.config.mjs';
556
-
557
- // Private workspace libs are compiled INTO this package's rollup bundle and
558
- // never declared in the manifest (a consumer could not install them), so the
559
- // dependency check must ignore them. Computed at lint time: adding a new
560
- // internal lib never requires touching this file.
561
- const workspaceRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
562
- const privateWorkspacePackages = globSync(['libs/*/package.json', 'packages/*/package.json'], { cwd: workspaceRoot })
563
- .map((manifestPath) => JSON.parse(readFileSync(join(workspaceRoot, manifestPath), 'utf8')))
564
- .filter((manifest) => manifest.private === true)
565
- .map((manifest) => manifest.name);
566
-
567
- export default [
568
- ...baseConfig,
569
- {
570
- files: ['**/*.json'],
571
- rules: {
572
- '@nx/dependency-checks': [
573
- 'error',
574
- {
575
- ignoredDependencies: privateWorkspacePackages,
576
- ignoredFiles: [
577
- '{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
578
- '{projectRoot}/rollup.config.{js,ts,mjs,mts,cjs,cts}',
579
- // Same reasoning as the two config files above, extended to the test
580
- // toolchain: rollup bundles from the entry point only, so neither the
581
- // Vitest config nor the spec files reach the published package \u2014 their
582
- // imports must not drive the published manifest.
583
- //
584
- // Without this, a vitest-stack workspace fails \`npm run lint\` on a
585
- // freshly generated npm-lib: Nx's own spec imports \`vitest\`, and
586
- // @nx/dependency-checks then demands it be declared as a runtime
587
- // dependency of a package that never uses it at runtime.
588
- '{projectRoot}/vitest.config.{js,ts,mjs,mts,cjs,cts}',
589
- '{projectRoot}/**/*.spec.{js,ts,jsx,tsx}',
590
- ],
591
- },
592
- ],
593
- },
594
- languageOptions: {
595
- parser: await import('jsonc-eslint-parser'),
596
- },
597
- },
598
- {
599
- ignores: ['**/out-tsc'],
600
- },
601
- ];
602
- `;
678
+ var import_node_path6 = require("path");
603
679
  async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
604
680
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
605
681
  runNx(
@@ -611,16 +687,14 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
611
687
  `--importPath=${scope}/${name}`,
612
688
  "--bundler=rollup",
613
689
  `--unitTestRunner=${stack.testRunner}`,
614
- "--linter=eslint",
690
+ "--linter=none",
615
691
  "--no-interactive"
616
692
  ],
617
693
  workspaceRoot
618
694
  );
619
- markPublic((0, import_node_path5.join)(workspaceRoot, "packages", name, "package.json"));
620
- writeFileEnsured(
621
- (0, import_node_path5.join)(workspaceRoot, "packages", name, "eslint.config.mjs"),
622
- NPM_LIB_ESLINT_CONFIG
623
- );
695
+ markPublic((0, import_node_path6.join)(workspaceRoot, "packages", name, "package.json"));
696
+ removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
697
+ registerProjectCommands(workspaceRoot, name, { build: true });
624
698
  }
625
699
  function markPublic(manifestPath) {
626
700
  const manifest = readJson(manifestPath);
@@ -628,8 +702,8 @@ function markPublic(manifestPath) {
628
702
  }
629
703
 
630
704
  // src/commands/add/python.ts
631
- var import_node_fs3 = require("fs");
632
- var import_node_path6 = require("path");
705
+ var import_node_fs4 = require("fs");
706
+ var import_node_path7 = require("path");
633
707
  function ensurePython(workspaceRoot) {
634
708
  const hasPython = runShell("python3", ["--version"], workspaceRoot) === 0 || runShell("python", ["--version"], workspaceRoot) === 0;
635
709
  if (!hasPython) {
@@ -658,7 +732,7 @@ pytest
658
732
  pip-audit
659
733
  `;
660
734
  function ensureRequirementsDev(workspaceRoot) {
661
- const requirementsDevPath = (0, import_node_path6.join)(workspaceRoot, "requirements-dev.txt");
735
+ const requirementsDevPath = (0, import_node_path7.join)(workspaceRoot, "requirements-dev.txt");
662
736
  if (!fileExists(requirementsDevPath)) {
663
737
  writeFileEnsured(requirementsDevPath, PYTHON_REQUIREMENTS_DEV);
664
738
  }
@@ -666,18 +740,40 @@ function ensureRequirementsDev(workspaceRoot) {
666
740
  function pythonModuleDirectory(name) {
667
741
  return name.replaceAll("-", "_");
668
742
  }
669
- function addProjectJsonTargets2(projectJsonPath, newTargets) {
743
+ function addProjectJsonTargets3(projectJsonPath, newTargets) {
670
744
  const project = readJson(projectJsonPath);
671
745
  const targets = project.targets ?? {};
672
746
  writeFileEnsured(projectJsonPath, toJson({ ...project, targets: { ...targets, ...newTargets } }));
673
747
  }
748
+ function pythonAppMain(name) {
749
+ return `def main() -> None:
750
+ print('${name} is running')
751
+
752
+
753
+ if __name__ == '__main__':
754
+ main()
755
+ `;
756
+ }
757
+ function pythonAppStartTarget(name) {
758
+ return {
759
+ executor: "nx:run-commands",
760
+ continuous: true,
761
+ options: { command: "python3 main.py", cwd: `apps/${name}` }
762
+ };
763
+ }
764
+ function pythonFunctionAppStartTarget(name) {
765
+ return {
766
+ executor: "nx:run-commands",
767
+ continuous: true,
768
+ options: { command: "func start", cwd: `apps/${name}` }
769
+ };
770
+ }
674
771
  function pythonAppPackageTarget(name) {
675
772
  const zip = `dist/drop/python-app-${name}.zip`;
676
773
  const command = `node -e "const fs=require('node:fs');fs.mkdirSync('dist/drop',{recursive:true});const A=require('adm-zip');const z=new A();z.addLocalFolder('apps/${name}/dist');z.writeZip('${zip}')"`;
677
774
  return {
678
775
  executor: "nx:run-commands",
679
776
  dependsOn: ["build"],
680
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
681
777
  outputs: [`{workspaceRoot}/${zip}`],
682
778
  options: { command }
683
779
  };
@@ -688,7 +784,6 @@ function pythonFunctionAppPackageTarget(name, moduleDirectory) {
688
784
  const command = `node -e "const fs=require('node:fs');fs.mkdirSync('dist/drop',{recursive:true});const A=require('adm-zip');const z=new A();z.addLocalFile('${root}/function_app.py');z.addLocalFile('${root}/host.json');z.addLocalFile('${root}/requirements.txt');z.addLocalFolder('${root}/${moduleDirectory}','${moduleDirectory}');z.writeZip('${zip}')"`;
689
785
  return {
690
786
  executor: "nx:run-commands",
691
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
692
787
  outputs: [`{workspaceRoot}/${zip}`],
693
788
  options: { command }
694
789
  };
@@ -702,9 +797,12 @@ function addPythonApp(workspaceRoot, name) {
702
797
  ["g", "@mnci/nx-python-pip:application", name, `--directory=apps/${name}`, "--no-interactive"],
703
798
  workspaceRoot
704
799
  );
705
- addProjectJsonTargets2((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
706
- package: pythonAppPackageTarget(name)
800
+ writeFileEnsured((0, import_node_path7.join)(workspaceRoot, "apps", name, "main.py"), pythonAppMain(name));
801
+ addProjectJsonTargets3((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
802
+ package: pythonAppPackageTarget(name),
803
+ start: pythonAppStartTarget(name)
707
804
  });
805
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:start` });
708
806
  }
709
807
  function addPythonFunctionApp(workspaceRoot, name) {
710
808
  ensurePython(workspaceRoot);
@@ -722,9 +820,11 @@ function addPythonFunctionApp(workspaceRoot, name) {
722
820
  workspaceRoot
723
821
  );
724
822
  const moduleDirectory = pythonModuleDirectory(name);
725
- addProjectJsonTargets2((0, import_node_path6.join)(workspaceRoot, "apps", name, "project.json"), {
726
- package: pythonFunctionAppPackageTarget(name, moduleDirectory)
823
+ addProjectJsonTargets3((0, import_node_path7.join)(workspaceRoot, "apps", name, "project.json"), {
824
+ package: pythonFunctionAppPackageTarget(name, moduleDirectory),
825
+ start: pythonFunctionAppStartTarget(name)
727
826
  });
827
+ registerProjectCommands(workspaceRoot, name, { build: false, start: `nx run ${name}:start` });
728
828
  }
729
829
  function addPythonLib(workspaceRoot, name) {
730
830
  ensurePython(workspaceRoot);
@@ -740,6 +840,7 @@ function addPythonLib(workspaceRoot, name) {
740
840
  ],
741
841
  workspaceRoot
742
842
  );
843
+ registerProjectCommands(workspaceRoot, name, { build: true });
743
844
  }
744
845
  function addPythonInternalLib(workspaceRoot, name) {
745
846
  ensurePython(workspaceRoot);
@@ -755,11 +856,12 @@ function addPythonInternalLib(workspaceRoot, name) {
755
856
  ],
756
857
  workspaceRoot
757
858
  );
859
+ registerProjectCommands(workspaceRoot, name, { build: false });
758
860
  }
759
861
  var PYTHON_PROJECT_DIRS = ["apps", "python-packages", "libs"];
760
862
  function findPythonProjectDirectory(workspaceRoot, name) {
761
863
  return PYTHON_PROJECT_DIRS.find(
762
- (directory) => fileExists((0, import_node_path6.join)(workspaceRoot, directory, name, "pyproject.toml"))
864
+ (directory) => fileExists((0, import_node_path7.join)(workspaceRoot, directory, name, "pyproject.toml"))
763
865
  );
764
866
  }
765
867
  function parseVendorEntries(pyprojectToml) {
@@ -798,7 +900,7 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
798
900
  `No Python project named '${consumer}' with a pyproject.toml found (checked apps/, python-packages/, libs/). A Python function app has no pyproject.toml \u2014 there is nothing to vendor into.`
799
901
  );
800
902
  }
801
- if (!fileExists((0, import_node_path6.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
903
+ if (!fileExists((0, import_node_path7.join)(workspaceRoot, "libs", lib, "pyproject.toml"))) {
802
904
  throw new Error(
803
905
  `No internal Python library named '${lib}' found at libs/${lib}/pyproject.toml. Only an internal library (added via 'mnci add python-internal-lib') can be vendored.`
804
906
  );
@@ -806,8 +908,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
806
908
  if (consumerDirectory === "libs" && consumer === lib) {
807
909
  throw new Error(`'${consumer}' cannot vendor itself.`);
808
910
  }
809
- const pyprojectPath = (0, import_node_path6.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
810
- const pyprojectToml = (0, import_node_fs3.readFileSync)(pyprojectPath, "utf8");
911
+ const pyprojectPath = (0, import_node_path7.join)(workspaceRoot, consumerDirectory, consumer, "pyproject.toml");
912
+ const pyprojectToml = (0, import_node_fs4.readFileSync)(pyprojectPath, "utf8");
811
913
  if (parseVendorEntries(pyprojectToml).includes(lib)) {
812
914
  logger.info(`'${consumer}' already vendors '${lib}' \u2014 nothing to do.`);
813
915
  return;
@@ -819,8 +921,8 @@ async function addPythonVendor(workspaceRoot, consumer, options, kindProvided) {
819
921
  }
820
922
 
821
923
  // src/commands/add/reactApp.ts
822
- var import_node_fs4 = require("fs");
823
- var import_node_path7 = require("path");
924
+ var import_node_fs5 = require("fs");
925
+ var import_node_path8 = require("path");
824
926
  function ensurePlugin2(workspaceRoot, packageName) {
825
927
  if (hasPlugin(workspaceRoot, packageName)) {
826
928
  return;
@@ -841,7 +943,6 @@ function reactAppTargets(name) {
841
943
  for (const environment of REACT_ENVIRONMENTS) {
842
944
  targets[`build-${environment}`] = {
843
945
  executor: "nx:run-commands",
844
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation -- {workspaceRoot} is an Nx output token
845
946
  outputs: [`{workspaceRoot}/apps/${name}/dist-${environment}`],
846
947
  options: {
847
948
  command: `vite build --mode ${environment} --outDir dist-${environment}`,
@@ -856,7 +957,6 @@ function reactAppTargets(name) {
856
957
  executor: "nx:run-commands",
857
958
  dependsOn: REACT_ENVIRONMENTS.map((environment) => `build-${environment}`),
858
959
  outputs: REACT_ENVIRONMENTS.map(
859
- // eslint-disable-next-line unicorn/no-incorrect-template-string-interpolation
860
960
  (environment) => `{workspaceRoot}/dist/drop/react-app-${name}-${environment}.zip`
861
961
  ),
862
962
  options: {
@@ -866,12 +966,12 @@ function reactAppTargets(name) {
866
966
  return targets;
867
967
  }
868
968
  function allowEnvFiles(workspaceRoot) {
869
- const gitignorePath = (0, import_node_path7.join)(workspaceRoot, ".gitignore");
969
+ const gitignorePath = (0, import_node_path8.join)(workspaceRoot, ".gitignore");
870
970
  if (!fileExists(gitignorePath)) {
871
971
  return;
872
972
  }
873
973
  const marker = "# MoNecromanCI: keep the committed per-environment Vite config (public VITE_ values)";
874
- const current = (0, import_node_fs4.readFileSync)(gitignorePath, "utf8");
974
+ const current = (0, import_node_fs5.readFileSync)(gitignorePath, "utf8");
875
975
  if (current.includes(marker)) {
876
976
  return;
877
977
  }
@@ -890,7 +990,7 @@ function addReactApp(workspaceRoot, name, stack) {
890
990
  `apps/${name}`,
891
991
  "--bundler=vite",
892
992
  `--unitTestRunner=${stack.testRunner}`,
893
- "--linter=eslint",
993
+ "--linter=none",
894
994
  "--style=css",
895
995
  "--e2eTestRunner=none",
896
996
  "--no-interactive"
@@ -898,12 +998,14 @@ function addReactApp(workspaceRoot, name, stack) {
898
998
  workspaceRoot
899
999
  );
900
1000
  ensureAdmZip(workspaceRoot);
901
- const reactAppRoot = (0, import_node_path7.join)(workspaceRoot, "apps", name);
1001
+ const reactAppRoot = (0, import_node_path8.join)(workspaceRoot, "apps", name);
902
1002
  for (const environment of REACT_ENVIRONMENTS) {
903
- writeFileEnsured((0, import_node_path7.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
1003
+ writeFileEnsured((0, import_node_path8.join)(reactAppRoot, `.env.${environment}`), reactEnvironmentFile(environment));
904
1004
  }
905
1005
  allowEnvFiles(workspaceRoot);
906
- addNxTargets((0, import_node_path7.join)(reactAppRoot, "package.json"), reactAppTargets(name));
1006
+ addNxTargets((0, import_node_path8.join)(reactAppRoot, "package.json"), reactAppTargets(name));
1007
+ removeGeneratedEslintConfig(workspaceRoot, `apps/${name}`);
1008
+ registerProjectCommands(workspaceRoot, name, { build: true, start: `nx run ${name}:serve` });
907
1009
  }
908
1010
 
909
1011
  // src/commands/add.ts
@@ -928,7 +1030,7 @@ var PROJECT_KINDS = [
928
1030
  ];
929
1031
  async function runAdd(kind, name, options) {
930
1032
  const workspaceRoot = process.cwd();
931
- if (!fileExists((0, import_node_path8.join)(workspaceRoot, "nx.json"))) {
1033
+ if (!fileExists((0, import_node_path9.join)(workspaceRoot, "nx.json"))) {
932
1034
  throw new Error("No nx.json found here. Run `add` from the workspace root.");
933
1035
  }
934
1036
  const stack = readWorkspaceStack(workspaceRoot);
@@ -964,12 +1066,14 @@ async function runAdd(kind, name, options) {
964
1066
  `libs/${resolvedName}`,
965
1067
  "--bundler=tsc",
966
1068
  `--unitTestRunner=${stack.testRunner}`,
967
- "--linter=eslint",
1069
+ "--linter=none",
968
1070
  "--no-interactive"
969
1071
  ],
970
1072
  workspaceRoot
971
1073
  );
972
- markPrivate((0, import_node_path8.join)(workspaceRoot, "libs", resolvedName, "package.json"));
1074
+ markPrivate((0, import_node_path9.join)(workspaceRoot, "libs", resolvedName, "package.json"));
1075
+ removeGeneratedEslintConfig(workspaceRoot, `libs/${resolvedName}`);
1076
+ registerProjectCommands(workspaceRoot, resolvedName, { build: true });
973
1077
  break;
974
1078
  }
975
1079
  case "python-app": {
@@ -1019,6 +1123,7 @@ async function runAdd(kind, name, options) {
1019
1123
  case "python-vendor": {
1020
1124
  await addPythonVendor(workspaceRoot, resolvedName, options, kindProvided);
1021
1125
  syncProjectReferences(workspaceRoot);
1126
+ runPrettier(workspaceRoot);
1022
1127
  return;
1023
1128
  }
1024
1129
  default: {
@@ -1029,6 +1134,7 @@ async function runAdd(kind, name, options) {
1029
1134
  }
1030
1135
  }
1031
1136
  syncProjectReferences(workspaceRoot);
1137
+ runPrettier(workspaceRoot);
1032
1138
  logger.success(`Added ${resolvedKind} '${resolvedName}'.`);
1033
1139
  }
1034
1140
  function syncProjectReferences(workspaceRoot) {
@@ -1041,7 +1147,7 @@ function syncProjectReferences(workspaceRoot) {
1041
1147
  }
1042
1148
  function readWorkspaceStack(workspaceRoot) {
1043
1149
  const nxJson = readJson(
1044
- (0, import_node_path8.join)(workspaceRoot, "nx.json")
1150
+ (0, import_node_path9.join)(workspaceRoot, "nx.json")
1045
1151
  );
1046
1152
  const stack = nxJson.mnci?.stack;
1047
1153
  return {
@@ -1054,48 +1160,31 @@ function markPrivate(manifestPath) {
1054
1160
  }
1055
1161
 
1056
1162
  // src/commands/interactive.ts
1057
- var import_node_path12 = require("path");
1163
+ var import_node_path13 = require("path");
1058
1164
  var import_prompts7 = require("@inquirer/prompts");
1059
1165
 
1060
1166
  // src/commands/new.ts
1061
- var import_node_path10 = require("path");
1167
+ var import_node_path11 = require("path");
1062
1168
 
1063
1169
  // src/overlay.ts
1064
- var import_node_path9 = require("path");
1170
+ var import_node_fs6 = require("fs");
1171
+ var import_node_path10 = require("path");
1065
1172
  var DEFAULT_STACK = { testRunner: "jest" };
1066
1173
  var PRETTIER_VERSION = "^3.8.1";
1067
1174
  var TS_COMPILER_DEPENDENCIES = {
1068
1175
  "@typescript/native": "npm:typescript@^7.0.2",
1069
1176
  typescript: "npm:@typescript/typescript6@^6.0.2"
1070
1177
  };
1071
- function npmrcContent(registry, scope) {
1072
- const scopeName = scope.replace(/^@/, "");
1073
- const lines = [
1074
- "registry=https://registry.npmjs.org/",
1075
- "; Community Nx plugins (e.g. the Azure Functions one) peer on the previous",
1076
- "; Nx major for a while after each release; accept the resolved tree.",
1077
- "legacy-peer-deps=true"
1078
- ];
1079
- if (registry.kind === "azure-artifacts") {
1080
- const base = `https://pkgs.dev.azure.com/${registry.organization}/${registry.project}/_packaging/${registry.artifactsFeed}`;
1081
- const registryHost = `${base}/npm/registry/`.replace(/^https:\/\//, "");
1082
- const feedHost = `${base}/`.replace(/^https:\/\//, "");
1083
- lines.push(
1084
- `@${scopeName}:registry=${base}/npm/registry/`,
1085
- "; Azure Artifacts auth \u2014 the base64 PAT is expanded at runtime from the",
1086
- "; PAT env var (CI: your PAT variable group; locally: export PAT=<base64 token>).",
1087
- `//${registryHost}:username=${registry.organization}`,
1088
- `//${registryHost}:_password=\${PAT}`,
1089
- `//${registryHost}:email=npm@example.com`,
1090
- `//${feedHost}:username=${registry.organization}`,
1091
- `//${feedHost}:_password=\${PAT}`,
1092
- `//${feedHost}:email=npm@example.com`
1093
- );
1094
- } else {
1095
- lines.push(`//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}`);
1096
- }
1097
- lines.push("");
1098
- return lines.join("\n");
1178
+ function npmrcContent(_registry, _scope) {
1179
+ return `; Intentionally empty.
1180
+ ;
1181
+ ; Publish authentication is not configured yet. The generated CI exports a
1182
+ ; token for the release step (NODE_AUTH_TOKEN for public npm, PAT for Azure
1183
+ ; Artifacts), but nothing here consumes it, so 'npm publish' will not
1184
+ ; authenticate until this is wired up.
1185
+ ;
1186
+ ; See "Known gaps" in the @mnci/cli README.
1187
+ `;
1099
1188
  }
1100
1189
  function releaseConfig(ci) {
1101
1190
  const githubReleases = ci === "github";
@@ -1122,6 +1211,18 @@ function releaseConfig(ci) {
1122
1211
  };
1123
1212
  }
1124
1213
  var SYNC_CONFIG = { applyChanges: true };
1214
+ var ESLINT_PLUGIN_CONFIG = {
1215
+ plugin: "@nx/eslint/plugin",
1216
+ options: { targetName: "lint" }
1217
+ };
1218
+ function pluginName(entry) {
1219
+ return typeof entry === "string" ? entry : entry.plugin;
1220
+ }
1221
+ function withEslintPlugin(nxJson) {
1222
+ const plugins = nxJson.plugins ?? [];
1223
+ const registered = plugins.some((entry) => pluginName(entry) === ESLINT_PLUGIN_CONFIG.plugin);
1224
+ return registered ? { ...nxJson, plugins } : { ...nxJson, plugins: [...plugins, ESLINT_PLUGIN_CONFIG] };
1225
+ }
1125
1226
  function withReleaseConfig(nxJson, ci) {
1126
1227
  return { ...nxJson, defaultBase: "main", release: releaseConfig(ci) };
1127
1228
  }
@@ -1132,13 +1233,30 @@ var COMMIT_MSG_HOOK = `npx --no -- commitlint --edit "$1"
1132
1233
  var PRETTIER_CONFIG = `{
1133
1234
  "semi": false,
1134
1235
  "singleQuote": true,
1135
- "trailingComma": "es5",
1236
+ "trailingComma": "none",
1136
1237
  "arrowParens": "avoid",
1137
1238
  "printWidth": 100,
1138
1239
  "tabWidth": 2,
1139
1240
  "useTabs": false
1140
1241
  }
1141
1242
  `;
1243
+ var ESLINT_CONFIG_VERSION = "^0.1.0";
1244
+ function eslintConfigSpec() {
1245
+ return process.env.MNCI_ESLINT_CONFIG_SPEC ?? ESLINT_CONFIG_VERSION;
1246
+ }
1247
+ var ESLINT_VERSION = "^9.39.0";
1248
+ function eslintToolchainDependencies(nxVersion) {
1249
+ return {
1250
+ eslint: ESLINT_VERSION,
1251
+ "@nx/eslint": nxVersion,
1252
+ "@nx/eslint-plugin": nxVersion,
1253
+ "@mnci/eslint-config": eslintConfigSpec()
1254
+ };
1255
+ }
1256
+ var ESLINT_CONFIG = `import mnci from '@mnci/eslint-config'
1257
+
1258
+ export default mnci({ workspaceRoot: import.meta.dirname })
1259
+ `;
1142
1260
  var PRETTIER_IGNORE = `node_modules
1143
1261
  dist
1144
1262
  dist-dev
@@ -1155,12 +1273,7 @@ package-lock.json
1155
1273
  function vscodeWorkspace(workspaceName) {
1156
1274
  return JSON.stringify(
1157
1275
  {
1158
- folders: [
1159
- { path: ".", name: workspaceName },
1160
- { path: "packages/cli", name: "@mnci/cli" },
1161
- { path: "packages/nx-python-pip", name: "@mnci/nx-python-pip" },
1162
- { path: "libs/monecromanci-v2", name: "@mnci/monecromanci" }
1163
- ],
1276
+ folders: [{ path: ".", name: workspaceName }],
1164
1277
  settings: {
1165
1278
  "eslint.validate": [
1166
1279
  "javascript",
@@ -1194,7 +1307,8 @@ function vscodeWorkspace(workspaceName) {
1194
1307
  "nrwl.angular-console",
1195
1308
  "firsttris.vscode-jest-runner"
1196
1309
  ]
1197
- }
1310
+ },
1311
+ tasks: { version: "2.0.0", tasks: [] }
1198
1312
  },
1199
1313
  null,
1200
1314
  2
@@ -1219,7 +1333,13 @@ function rootScripts() {
1219
1333
  }
1220
1334
  function generatorDefaults(stack) {
1221
1335
  const shared = {
1222
- linter: "eslint",
1336
+ // `none`, not `eslint`, and the workspace is still fully linted. The root
1337
+ // config plus `@nx/eslint/plugin` ({@link ESLINT_PLUGIN_CONFIG}) give every
1338
+ // project its `lint` target; `eslint` here would only make the generator
1339
+ // scaffold a per-project config mnci deletes anyway — and drag in
1340
+ // `eslint-plugin-import@2.31.0`, which peer-caps at ESLint 9 and breaks the
1341
+ // install outright on this workspace's ESLint 10.
1342
+ linter: "none",
1223
1343
  unitTestRunner: stack.testRunner
1224
1344
  };
1225
1345
  return {
@@ -1239,7 +1359,7 @@ function mnciConfig(options) {
1239
1359
  };
1240
1360
  }
1241
1361
  function readMnciConfig(workspaceRoot) {
1242
- const nxJson = readJson((0, import_node_path9.join)(workspaceRoot, "nx.json"));
1362
+ const nxJson = readJson((0, import_node_path10.join)(workspaceRoot, "nx.json"));
1243
1363
  return nxJson.mnci ?? {};
1244
1364
  }
1245
1365
  function pythonPublishUrl(registry) {
@@ -1664,8 +1784,23 @@ updates:
1664
1784
  schedule:
1665
1785
  interval: weekly
1666
1786
  `;
1787
+ var NX_SCAFFOLDING_TO_REMOVE = [".prettierrc", ".vscode"];
1788
+ function removeNxScaffolding(workspaceRoot) {
1789
+ for (const entry of NX_SCAFFOLDING_TO_REMOVE) {
1790
+ (0, import_node_fs6.rmSync)((0, import_node_path10.join)(workspaceRoot, entry), { recursive: true, force: true });
1791
+ }
1792
+ removeProjectEslintConfigs(workspaceRoot);
1793
+ }
1794
+ function removeProjectEslintConfigs(workspaceRoot) {
1795
+ const matches = (0, import_node_fs6.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
1796
+ cwd: workspaceRoot
1797
+ });
1798
+ for (const match of matches) {
1799
+ (0, import_node_fs6.rmSync)((0, import_node_path10.join)(workspaceRoot, match), { force: true });
1800
+ }
1801
+ }
1667
1802
  function applyOverlay(workspaceRoot, options) {
1668
- const nxJsonPath = (0, import_node_path9.join)(workspaceRoot, "nx.json");
1803
+ const nxJsonPath = (0, import_node_path10.join)(workspaceRoot, "nx.json");
1669
1804
  const nxJson = readJson(nxJsonPath);
1670
1805
  const generators = {
1671
1806
  ...nxJson.generators,
@@ -1673,49 +1808,52 @@ function applyOverlay(workspaceRoot, options) {
1673
1808
  };
1674
1809
  const sync = { ...nxJson.sync, ...SYNC_CONFIG };
1675
1810
  const mnci = { ...nxJson.mnci, ...mnciConfig(options) };
1676
- writeFileEnsured(
1677
- nxJsonPath,
1678
- toJson({ ...withReleaseConfig(nxJson, options.ci), generators, sync, mnci })
1679
- );
1680
- const manifestPath = (0, import_node_path9.join)(workspaceRoot, "package.json");
1811
+ const patched = withEslintPlugin(withReleaseConfig(nxJson, options.ci));
1812
+ writeFileEnsured(nxJsonPath, toJson({ ...patched, generators, sync, mnci }));
1813
+ const manifestPath = (0, import_node_path10.join)(workspaceRoot, "package.json");
1681
1814
  const manifest = readJson(manifestPath);
1682
1815
  const scripts = {
1683
1816
  ...manifest.scripts,
1684
1817
  ...rootScripts()
1685
1818
  };
1819
+ const existingDevDeps = manifest.devDependencies;
1686
1820
  const devDeps = {
1687
- ...manifest.devDependencies,
1821
+ ...existingDevDeps,
1688
1822
  ...TS_COMPILER_DEPENDENCIES,
1823
+ // The preset pins `nx` itself; the ESLint plugins must match it exactly.
1824
+ ...eslintToolchainDependencies(existingDevDeps?.nx ?? "latest"),
1689
1825
  prettier: PRETTIER_VERSION
1690
1826
  };
1691
1827
  writeFileEnsured(
1692
1828
  manifestPath,
1693
1829
  toJson({ ...manifest, name: `${options.scope}/source`, scripts, devDependencies: devDeps })
1694
1830
  );
1695
- writeFileEnsured((0, import_node_path9.join)(workspaceRoot, ".npmrc"), npmrcContent(options.registry, options.scope));
1696
- writeFileEnsured((0, import_node_path9.join)(workspaceRoot, "commitlint.config.mjs"), COMMITLINT_CONFIG);
1697
- const hookPath = (0, import_node_path9.join)(workspaceRoot, ".husky/commit-msg");
1831
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, ".npmrc"), npmrcContent(options.registry, options.scope));
1832
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, "commitlint.config.mjs"), COMMITLINT_CONFIG);
1833
+ const hookPath = (0, import_node_path10.join)(workspaceRoot, ".husky/commit-msg");
1698
1834
  writeFileEnsured(hookPath, COMMIT_MSG_HOOK);
1699
1835
  markExecutable(hookPath);
1700
- writeFileEnsured((0, import_node_path9.join)(workspaceRoot, ".prettierrc.json"), PRETTIER_CONFIG);
1701
- writeFileEnsured((0, import_node_path9.join)(workspaceRoot, ".prettierignore"), PRETTIER_IGNORE);
1836
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, "eslint.config.mjs"), ESLINT_CONFIG);
1837
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, ".prettierrc.json"), PRETTIER_CONFIG);
1838
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, ".prettierignore"), PRETTIER_IGNORE);
1839
+ removeNxScaffolding(workspaceRoot);
1702
1840
  writeFileEnsured(
1703
- (0, import_node_path9.join)(workspaceRoot, `${options.workspaceName}.code-workspace`),
1841
+ (0, import_node_path10.join)(workspaceRoot, `${options.workspaceName}.code-workspace`),
1704
1842
  vscodeWorkspace(options.workspaceName)
1705
1843
  );
1706
1844
  const publishUrl = pythonPublishUrl(options.registry);
1707
1845
  if (options.ci === "azure" || options.ci === "both") {
1708
1846
  writeFileEnsured(
1709
- (0, import_node_path9.join)(workspaceRoot, "azure-pipelines.yml"),
1847
+ (0, import_node_path10.join)(workspaceRoot, "azure-pipelines.yml"),
1710
1848
  azurePipelinesYaml(options.agent, options.variableGroup, publishUrl, options.registry.kind)
1711
1849
  );
1712
1850
  }
1713
1851
  if (options.ci === "github" || options.ci === "both") {
1714
1852
  writeFileEnsured(
1715
- (0, import_node_path9.join)(workspaceRoot, ".github/workflows/ci.yml"),
1853
+ (0, import_node_path10.join)(workspaceRoot, ".github/workflows/ci.yml"),
1716
1854
  githubActionsYaml(options.agent, publishUrl, options.registry.kind, options.ci)
1717
1855
  );
1718
- writeFileEnsured((0, import_node_path9.join)(workspaceRoot, ".github/dependabot.yml"), DEPENDABOT_CONFIG);
1856
+ writeFileEnsured((0, import_node_path10.join)(workspaceRoot, ".github/dependabot.yml"), DEPENDABOT_CONFIG);
1719
1857
  }
1720
1858
  }
1721
1859
 
@@ -1784,12 +1922,12 @@ async function runNew(name, options) {
1784
1922
  ],
1785
1923
  process.cwd()
1786
1924
  );
1787
- const workspaceRoot = (0, import_node_path10.join)(process.cwd(), workspaceName);
1925
+ const workspaceRoot = (0, import_node_path11.join)(process.cwd(), workspaceName);
1788
1926
  logger.step(
1789
1927
  "Applying MoNecromanCI overlay (VS Code workspace, release config, .npmrc, commitlint, pipeline, stack)"
1790
1928
  );
1791
1929
  applyOverlay(workspaceRoot, { workspaceName, scope, registry, agent, variableGroup, ci, stack });
1792
- logger.step("Installing the toolchain (commitlint + husky)");
1930
+ logger.step("Installing the toolchain (commitlint + husky + linting/formatting)");
1793
1931
  const installStatus = runShell(
1794
1932
  "npm",
1795
1933
  ["install", "--save-dev", "husky", "@commitlint/cli", "@commitlint/config-conventional"],
@@ -1799,6 +1937,8 @@ async function runNew(name, options) {
1799
1937
  throw new Error(`npm install of the toolchain failed with exit code ${installStatus}`);
1800
1938
  }
1801
1939
  runShell("npx", ["husky"], workspaceRoot);
1940
+ logger.step("Formatting the workspace (Prettier, JavaScript Standard Style)");
1941
+ runPrettier(workspaceRoot);
1802
1942
  logger.success("Done. Next steps:");
1803
1943
  logger.info(` cd ${workspaceName}`);
1804
1944
  logger.info(
@@ -1817,7 +1957,7 @@ async function runNew(name, options) {
1817
1957
  }
1818
1958
 
1819
1959
  // src/commands/upgrade.ts
1820
- var import_node_path11 = require("path");
1960
+ var import_node_path12 = require("path");
1821
1961
  function resolveRegistry2(options, persisted) {
1822
1962
  if (options.registry === "azure-artifacts" || options.organization && options.artifactsFeed) {
1823
1963
  const persistedAzure = persisted?.kind === "azure-artifacts" ? persisted : void 0;
@@ -1869,7 +2009,7 @@ function resolveOverlayOptions(options, persisted) {
1869
2009
  return { scope, registry, agent, variableGroup, ci, stack: { testRunner } };
1870
2010
  }
1871
2011
  function runUpgrade(workspaceRoot, options) {
1872
- if (!fileExists((0, import_node_path11.join)(workspaceRoot, "nx.json"))) {
2012
+ if (!fileExists((0, import_node_path12.join)(workspaceRoot, "nx.json"))) {
1873
2013
  throw new Error(
1874
2014
  `No nx.json found in ${workspaceRoot} \u2014 this does not look like an Nx workspace. Run 'mnci upgrade' from the workspace root.`
1875
2015
  );
@@ -1885,7 +2025,7 @@ function runUpgrade(workspaceRoot, options) {
1885
2025
 
1886
2026
  // src/commands/interactive.ts
1887
2027
  async function runInteractive() {
1888
- const inWorkspace = fileExists((0, import_node_path12.join)(process.cwd(), "nx.json"));
2028
+ const inWorkspace = fileExists((0, import_node_path13.join)(process.cwd(), "nx.json"));
1889
2029
  const newChoice = { name: "Create a new monorepo", value: "new" };
1890
2030
  const addChoice = { name: "Add a project to this workspace", value: "add" };
1891
2031
  const upgradeChoice = {
@@ -1906,8 +2046,8 @@ async function runInteractive() {
1906
2046
  }
1907
2047
 
1908
2048
  // src/util/versionChecker.ts
1909
- var import_node_fs5 = require("fs");
1910
- var import_node_path13 = require("path");
2049
+ var import_node_fs7 = require("fs");
2050
+ var import_node_path14 = require("path");
1911
2051
  var import_cross_spawn2 = __toESM(require("cross-spawn"));
1912
2052
  var PACKAGE_NAME = "@mnci/cli";
1913
2053
  var REGISTRY_TIMEOUT_MS = 2e3;
@@ -1963,8 +2103,8 @@ function releaseTriple(version) {
1963
2103
  }
1964
2104
  function readCliVersion(packageDirectory) {
1965
2105
  try {
1966
- const manifestPath = (0, import_node_path13.join)(packageDirectory, "..", "package.json");
1967
- const manifest = JSON.parse((0, import_node_fs5.readFileSync)(manifestPath, "utf8"));
2106
+ const manifestPath = (0, import_node_path14.join)(packageDirectory, "..", "package.json");
2107
+ const manifest = JSON.parse((0, import_node_fs7.readFileSync)(manifestPath, "utf8"));
1968
2108
  return manifest.version ?? "0.0.0";
1969
2109
  } catch {
1970
2110
  return "0.0.0";