@nanoforge-dev/cli 1.0.0 → 1.1.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.
@@ -11,7 +11,7 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  };
12
12
 
13
13
  // src/command/command.loader.ts
14
- import { red as red6 } from "ansis";
14
+ import { red as red8 } from "ansis";
15
15
 
16
16
  // src/lib/ui/messages.ts
17
17
  import { green } from "ansis";
@@ -41,7 +41,9 @@ var Emojis = {
41
41
  // src/lib/ui/messages.ts
42
42
  var Messages = {
43
43
  BUILD_START: "NanoForge Build",
44
- BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}...`, "BUILD_PART_IN_PROGRESS"),
44
+ BUILD_WATCH_START: "Start watching mode",
45
+ BUILD_PART_IN_PROGRESS: /* @__PURE__ */ __name((part) => `Building ${part}`, "BUILD_PART_IN_PROGRESS"),
46
+ BUILD_PART_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((part) => `${part} updated. Rebuilding`, "BUILD_PART_WATCH_IN_PROGRESS"),
45
47
  BUILD_NOTHING: "Nothing to build, terminated.",
46
48
  BUILD_SUCCESS: `${Emojis.ROCKET} Build succeeded !`,
47
49
  BUILD_PART_FAILED: /* @__PURE__ */ __name((part, commandToRunManually) => `${Emojis.SCREAM} Build of ${part} failed !
@@ -58,8 +60,16 @@ In case you don't see any errors above, consider manually running the failed com
58
60
  NEW_STRICT_QUESTION: "Do you want to use types strict mode ?",
59
61
  NEW_SERVER_QUESTION: "Do you want generate a server to create a multiplayer game ?",
60
62
  NEW_SKIP_INSTALL_QUESTION: "Do you want to skip installation ?",
63
+ GENERATE_START: "NanoForge Generate",
64
+ GENERATE_WATCH_START: "Start watching mode",
65
+ GENERATE_SUCCESS: `${Emojis.ROCKET} Generate succeeded !`,
66
+ GENERATE_FAILED: `${Emojis.SCREAM} Generate failed !`,
67
+ DEV_START: "NanoForge Dev mode",
68
+ DEV_SUCCESS: "Dev mode ended",
69
+ DEV_FAILED: `${Emojis.SCREAM} Dev failed !`,
61
70
  SCHEMATICS_START: "Schematics execution",
62
71
  SCHEMATIC_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Executing schematic ${name}...`, "SCHEMATIC_IN_PROGRESS"),
72
+ SCHEMATIC_WATCH_IN_PROGRESS: /* @__PURE__ */ __name((name) => `Update watched. Executing schematic ${name}...`, "SCHEMATIC_WATCH_IN_PROGRESS"),
63
73
  SCHEMATIC_SUCCESS: /* @__PURE__ */ __name((name) => `${Emojis.ROCKET} Schematic ${name} executed successfully !`, "SCHEMATIC_SUCCESS"),
64
74
  SCHEMATIC_FAILED: /* @__PURE__ */ __name((name) => `${Emojis.SCREAM} Schematic ${name} execution failed. See error below for more details.`, "SCHEMATIC_FAILED"),
65
75
  PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS: `Installation in progress... ${Emojis.COFFEE}`,
@@ -84,7 +94,9 @@ var Prefixes = {
84
94
 
85
95
  // src/action/actions/build.action.ts
86
96
  import * as ansis from "ansis";
87
- import * as process3 from "process";
97
+ import { watch } from "chokidar";
98
+ import * as console2 from "console";
99
+ import { dirname, join as join2 } from "path";
88
100
 
89
101
  // src/lib/input/base-inputs.ts
90
102
  var getStringInput = /* @__PURE__ */ __name((input2, field) => {
@@ -133,6 +145,16 @@ var getConfigInput = /* @__PURE__ */ __name((inputs) => {
133
145
  return getStringInputWithDefault(inputs, "config", ".");
134
146
  }, "getConfigInput");
135
147
 
148
+ // src/lib/input/inputs/watch.input.ts
149
+ var getWatchInput = /* @__PURE__ */ __name((inputs) => {
150
+ return getBooleanInputWithDefault(inputs, "watch", false);
151
+ }, "getWatchInput");
152
+
153
+ // src/lib/input/inputs/dev/generate.input.ts
154
+ var getDevGenerateInput = /* @__PURE__ */ __name((inputs) => {
155
+ return getBooleanInputWithDefault(inputs, "generate", false);
156
+ }, "getDevGenerateInput");
157
+
136
158
  // src/lib/question/questions/confirm.question.ts
137
159
  import { confirm } from "@inquirer/prompts";
138
160
 
@@ -214,6 +236,10 @@ var getInstallNamesInputOrAsk = /* @__PURE__ */ __name((inputs) => {
214
236
  );
215
237
  }, "getInstallNamesInputOrAsk");
216
238
 
239
+ // src/lib/package-manager/package-manager.factory.ts
240
+ import fs from "fs";
241
+ import { resolve as resolve2 } from "path";
242
+
217
243
  // src/lib/runner/runner.factory.ts
218
244
  import { yellow } from "ansis";
219
245
 
@@ -236,7 +262,7 @@ var AbstractRunner = class {
236
262
  shell: true,
237
263
  env: { ...process2.env, ...env2 }
238
264
  };
239
- return new Promise((resolve, reject) => {
265
+ return new Promise((resolve3, reject) => {
240
266
  const child = spawn(
241
267
  `${this.binary} ${[...this.args, ...args].join(" ")}`,
242
268
  options
@@ -252,7 +278,7 @@ var AbstractRunner = class {
252
278
  );
253
279
  child.on("close", (code) => {
254
280
  if (code === 0) {
255
- resolve(collect && res.length ? res.join("\n") : null);
281
+ resolve3(collect && res.length ? res.join("\n") : null);
256
282
  } else {
257
283
  if (failSpinner) failSpinner();
258
284
  console.error(
@@ -285,15 +311,48 @@ var BunRunner = class extends AbstractRunner {
285
311
  };
286
312
 
287
313
  // src/lib/utils/path.ts
288
- import { join } from "path";
314
+ import { resolve } from "path";
289
315
  var getCwd = /* @__PURE__ */ __name((directory) => {
290
- return directory.startsWith("/") ? directory : join(process.cwd(), directory);
316
+ return resolve(directory);
291
317
  }, "getCwd");
292
318
  var getModulePath = /* @__PURE__ */ __name((name, removeLast = false) => {
293
319
  const path = import.meta.resolve(name).replace(/^file:\/\//, "");
294
320
  if (removeLast) return path.split("/").slice(0, -1).join("/");
295
321
  return path;
296
322
  }, "getModulePath");
323
+ var getNodeBinaryPath = /* @__PURE__ */ __name((name) => {
324
+ return resolve("node_modules", ".bin", name);
325
+ }, "getNodeBinaryPath");
326
+
327
+ // src/lib/runner/runners/local-bun.runner.ts
328
+ var LocalBunRunner = class extends AbstractRunner {
329
+ static {
330
+ __name(this, "LocalBunRunner");
331
+ }
332
+ constructor() {
333
+ super(getNodeBinaryPath("bun"));
334
+ }
335
+ };
336
+
337
+ // src/lib/runner/runners/npm.runner.ts
338
+ var NpmRunner = class extends AbstractRunner {
339
+ static {
340
+ __name(this, "NpmRunner");
341
+ }
342
+ constructor() {
343
+ super("npm");
344
+ }
345
+ };
346
+
347
+ // src/lib/runner/runners/pnpm.runner.ts
348
+ var PnpmRunner = class extends AbstractRunner {
349
+ static {
350
+ __name(this, "PnpmRunner");
351
+ }
352
+ constructor() {
353
+ super("pnpm");
354
+ }
355
+ };
297
356
 
298
357
  // src/lib/runner/runners/schematic.runner.ts
299
358
  var SchematicRunner = class _SchematicRunner extends AbstractRunner {
@@ -316,6 +375,16 @@ var SchematicRunner = class _SchematicRunner extends AbstractRunner {
316
375
  }
317
376
  };
318
377
 
378
+ // src/lib/runner/runners/yarn.runner.ts
379
+ var YarnRunner = class extends AbstractRunner {
380
+ static {
381
+ __name(this, "YarnRunner");
382
+ }
383
+ constructor() {
384
+ super("yarn");
385
+ }
386
+ };
387
+
319
388
  // src/lib/runner/runner.factory.ts
320
389
  var RunnerFactory = class {
321
390
  static {
@@ -325,8 +394,16 @@ var RunnerFactory = class {
325
394
  switch (runner) {
326
395
  case 0 /* BUN */:
327
396
  return new BunRunner();
328
- case 1 /* SCHEMATIC */:
397
+ case 1 /* LOCAL_BUN */:
398
+ return new LocalBunRunner();
399
+ case 2 /* NPM */:
400
+ return new NpmRunner();
401
+ case 3 /* PNPM */:
402
+ return new PnpmRunner();
403
+ case 4 /* SCHEMATIC */:
329
404
  return new SchematicRunner();
405
+ case 5 /* YARN */:
406
+ return new YarnRunner();
330
407
  default:
331
408
  console.info(yellow`[WARN] Unsupported runner: ${runner}`);
332
409
  throw Error(`Unsupported runner: ${runner}`);
@@ -383,9 +460,11 @@ var AbstractPackageManager = class {
383
460
  const command = [this.cli.add, this.cli.saveDevFlag];
384
461
  return this.add(command, directory, dependencies);
385
462
  }
386
- async build(name, directory, entry, output, flags) {
463
+ async build(name, directory, entry, output, flags, watch3) {
387
464
  if (!this.cli.build) throw new Error(`Package manager ${this.name} does not support building`);
388
- const spinner = SPINNER(Messages.BUILD_PART_IN_PROGRESS(name));
465
+ const spinner = SPINNER(
466
+ (watch3 ? Messages.BUILD_PART_WATCH_IN_PROGRESS : Messages.BUILD_PART_IN_PROGRESS)(name)
467
+ );
389
468
  spinner.start();
390
469
  try {
391
470
  const commandArgs = [
@@ -415,7 +494,6 @@ var AbstractPackageManager = class {
415
494
  }
416
495
  }
417
496
  async run(name, directory, file, env2 = {}, flags = [], silent = false) {
418
- if (!this.cli.run) throw new Error(`Package manager ${this.name} does not support running`);
419
497
  try {
420
498
  console.info(Messages.RUN_PART_IN_PROGRESS(name));
421
499
  const commandArgs = [...flags, this.cli.run];
@@ -432,6 +510,15 @@ var AbstractPackageManager = class {
432
510
  return false;
433
511
  }
434
512
  }
513
+ async runDev(directory, command, env2 = {}, flags = [], collect = true) {
514
+ try {
515
+ const commandArgs = [this.cli.run, command, ...flags];
516
+ await this.runner.run(commandArgs, collect, getCwd(directory), env2);
517
+ return true;
518
+ } catch {
519
+ return false;
520
+ }
521
+ }
435
522
  async add(args, directory, dependencies) {
436
523
  if (!dependencies.length) {
437
524
  console.info();
@@ -503,7 +590,6 @@ var BunPackageManager = class extends AbstractPackageManager {
503
590
  add: "add",
504
591
  update: "update",
505
592
  remove: "remove",
506
- build: "build",
507
593
  run: "run",
508
594
  saveFlag: "--save",
509
595
  saveDevFlag: "--dev",
@@ -512,6 +598,108 @@ var BunPackageManager = class extends AbstractPackageManager {
512
598
  }
513
599
  };
514
600
 
601
+ // src/lib/package-manager/package-managers/local-bun.package-manager.ts
602
+ var LocalBunPackageManager = class extends AbstractPackageManager {
603
+ static {
604
+ __name(this, "LocalBunPackageManager");
605
+ }
606
+ constructor() {
607
+ super(RunnerFactory.create(1 /* LOCAL_BUN */));
608
+ }
609
+ get name() {
610
+ return "local_bun" /* LOCAL_BUN */.toUpperCase();
611
+ }
612
+ get cli() {
613
+ return {
614
+ install: "install",
615
+ add: "add",
616
+ update: "update",
617
+ remove: "remove",
618
+ run: "run",
619
+ build: "build",
620
+ runFile: "run",
621
+ saveFlag: "--save",
622
+ saveDevFlag: "--dev",
623
+ silentFlag: "--silent"
624
+ };
625
+ }
626
+ };
627
+
628
+ // src/lib/package-manager/package-managers/npm.package-manager.ts
629
+ var NpmPackageManager = class extends AbstractPackageManager {
630
+ static {
631
+ __name(this, "NpmPackageManager");
632
+ }
633
+ constructor() {
634
+ super(RunnerFactory.create(2 /* NPM */));
635
+ }
636
+ get name() {
637
+ return "npm" /* NPM */.toUpperCase();
638
+ }
639
+ get cli() {
640
+ return {
641
+ install: "install",
642
+ add: "install",
643
+ update: "update",
644
+ remove: "uninstall",
645
+ run: "run",
646
+ saveFlag: "--save",
647
+ saveDevFlag: "--save-dev",
648
+ silentFlag: "--silent"
649
+ };
650
+ }
651
+ };
652
+
653
+ // src/lib/package-manager/package-managers/pnpm.package-manager.ts
654
+ var PnpmPackageManager = class extends AbstractPackageManager {
655
+ static {
656
+ __name(this, "PnpmPackageManager");
657
+ }
658
+ constructor() {
659
+ super(RunnerFactory.create(3 /* PNPM */));
660
+ }
661
+ get name() {
662
+ return "pnpm" /* PNPM */.toUpperCase();
663
+ }
664
+ get cli() {
665
+ return {
666
+ install: "install",
667
+ add: "add",
668
+ update: "update",
669
+ remove: "remove",
670
+ run: "run",
671
+ saveFlag: "-P",
672
+ saveDevFlag: "-D",
673
+ silentFlag: "--silent"
674
+ };
675
+ }
676
+ };
677
+
678
+ // src/lib/package-manager/package-managers/yarn.package-manager.ts
679
+ var YarnPackageManager = class extends AbstractPackageManager {
680
+ static {
681
+ __name(this, "YarnPackageManager");
682
+ }
683
+ constructor() {
684
+ super(RunnerFactory.create(5 /* YARN */));
685
+ }
686
+ get name() {
687
+ return "yarn" /* YARN */.toUpperCase();
688
+ }
689
+ get cli() {
690
+ return {
691
+ install: "install",
692
+ add: "add",
693
+ update: "update",
694
+ remove: "remove",
695
+ run: "run",
696
+ saveFlag: "",
697
+ saveDevFlag: "-D",
698
+ silentFlag: "--silent"
699
+ };
700
+ }
701
+ };
702
+
515
703
  // src/lib/package-manager/package-manager.factory.ts
516
704
  var PackageManagerFactory = class {
517
705
  static {
@@ -521,10 +709,39 @@ var PackageManagerFactory = class {
521
709
  switch (name) {
522
710
  case "bun" /* BUN */:
523
711
  return new BunPackageManager();
712
+ case "local_bun" /* LOCAL_BUN */:
713
+ return new LocalBunPackageManager();
714
+ case "npm" /* NPM */:
715
+ return new NpmPackageManager();
716
+ case "pnpm" /* PNPM */:
717
+ return new PnpmPackageManager();
718
+ case "yarn" /* YARN */:
719
+ return new YarnPackageManager();
524
720
  default:
525
721
  throw new Error(`Package manager ${name} is not managed.`);
526
722
  }
527
723
  }
724
+ static async find(directory = ".") {
725
+ const DEFAULT_PACKAGE_MANAGER = "npm" /* NPM */;
726
+ try {
727
+ const files = await fs.promises.readdir(resolve2(directory));
728
+ if (files.includes("bun.lock")) {
729
+ return this.create("bun" /* BUN */);
730
+ }
731
+ if (files.includes("package-lock.json")) {
732
+ return this.create("npm" /* NPM */);
733
+ }
734
+ if (files.includes("pnpm-lock.yaml")) {
735
+ return this.create("pnpm" /* PNPM */);
736
+ }
737
+ if (files.includes("yarn.lock")) {
738
+ return this.create("yarn" /* YARN */);
739
+ }
740
+ return this.create(DEFAULT_PACKAGE_MANAGER);
741
+ } catch {
742
+ return this.create(DEFAULT_PACKAGE_MANAGER);
743
+ }
744
+ }
528
745
  };
529
746
 
530
747
  // src/lib/config/config.type.ts
@@ -650,7 +867,7 @@ __decorateClass([
650
867
  import { plainToInstance } from "class-transformer";
651
868
  import { validate } from "class-validator";
652
869
  import { existsSync, readFileSync } from "fs";
653
- import { join as join2 } from "path";
870
+ import { join } from "path";
654
871
 
655
872
  // src/lib/utils/object.ts
656
873
  var isObject = /* @__PURE__ */ __name((item) => {
@@ -705,10 +922,10 @@ var CONFIG_DEFAULTS = {
705
922
  var config;
706
923
  var getConfigPath = /* @__PURE__ */ __name((directory, name) => {
707
924
  if (name) {
708
- return join2(directory, name);
925
+ return join(directory, name);
709
926
  } else {
710
927
  for (const n of ["nanoforge.config.json"]) {
711
- const path = join2(directory, n);
928
+ const path = join(directory, n);
712
929
  if (existsSync(path)) return path;
713
930
  }
714
931
  throw new Error(`Unsupported config: ${name}`);
@@ -754,32 +971,38 @@ var BuildAction = class extends AbstractAction {
754
971
  __name(this, "BuildAction");
755
972
  }
756
973
  async handle(_args, options) {
757
- console.info(Messages.BUILD_START);
758
- console.info();
974
+ console2.info(Messages.BUILD_START);
975
+ console2.info();
759
976
  try {
760
977
  const directory = getDirectoryInput(options);
761
978
  const config2 = await getConfig(options, directory);
979
+ const watch3 = getWatchInput(options);
762
980
  const client = getPart(
763
981
  config2.client.build,
764
982
  options.get("clientDirectory")?.value,
765
983
  "client"
766
984
  );
767
- let res = await buildPart("Client", client, directory);
985
+ let res = await buildPart("Client", client, directory, { watch: watch3 });
768
986
  if (config2.server.enable) {
769
987
  const server = getPart(
770
988
  config2.server.build,
771
989
  options.get("serverDirectory")?.value,
772
990
  "server"
773
991
  );
774
- res = await buildPart("Server", server, directory) ? res : false;
992
+ res = await buildPart("Server", server, directory, { watch: watch3 }) ? res : false;
775
993
  }
776
- console.info();
777
- if (!res) console.info(Messages.BUILD_FAILED);
778
- else console.info(Messages.BUILD_SUCCESS);
779
- process3.exit(0);
994
+ console2.info();
995
+ if (watch3) {
996
+ console2.info(Messages.BUILD_WATCH_START);
997
+ console2.info();
998
+ return;
999
+ }
1000
+ if (!res) console2.info(Messages.BUILD_FAILED);
1001
+ else console2.info(Messages.BUILD_SUCCESS);
1002
+ process.exit(0);
780
1003
  } catch (e) {
781
- console.error(e);
782
- process3.exit(1);
1004
+ console2.error(e);
1005
+ process.exit(1);
783
1006
  }
784
1007
  }
785
1008
  };
@@ -790,26 +1013,76 @@ var getPart = /* @__PURE__ */ __name((config2, directoryOption, target) => {
790
1013
  target
791
1014
  };
792
1015
  }, "getPart");
793
- var buildPart = /* @__PURE__ */ __name(async (name, part, directory) => {
794
- const packageManagerName = "bun" /* BUN */;
1016
+ var buildPart = /* @__PURE__ */ __name(async (name, part, directory, options) => {
1017
+ const packageManagerName = "local_bun" /* LOCAL_BUN */;
1018
+ const packageManager = PackageManagerFactory.create(packageManagerName);
1019
+ const build = /* @__PURE__ */ __name(async (watch3 = false) => {
1020
+ try {
1021
+ return await packageManager.build(
1022
+ name,
1023
+ directory,
1024
+ part.entry,
1025
+ part.output,
1026
+ [
1027
+ "--asset-naming",
1028
+ "[name].[ext]",
1029
+ "--target",
1030
+ part.target === "client" ? "browser" : "node"
1031
+ ],
1032
+ watch3
1033
+ );
1034
+ } catch (error4) {
1035
+ if (error4 && error4.message) {
1036
+ console2.error(ansis.red(error4.message));
1037
+ }
1038
+ return false;
1039
+ }
1040
+ }, "build");
1041
+ if (options?.watch)
1042
+ watch(dirname(join2(getCwd(directory), part.entry))).on("change", () => build(true));
1043
+ return await build();
1044
+ }, "buildPart");
1045
+
1046
+ // src/action/actions/dev.action.ts
1047
+ import * as ansis2 from "ansis";
1048
+ var DevAction = class extends AbstractAction {
1049
+ static {
1050
+ __name(this, "DevAction");
1051
+ }
1052
+ async handle(_args, options) {
1053
+ console.info(Messages.DEV_START);
1054
+ console.info();
1055
+ try {
1056
+ const directory = getDirectoryInput(options);
1057
+ const generate = getDevGenerateInput(options);
1058
+ await Promise.all([
1059
+ generate ? runAction("generate", [], directory, false) : void 0,
1060
+ runAction("build", [], directory, false),
1061
+ runAction("start", [], directory, true)
1062
+ ]);
1063
+ console.info(Messages.DEV_SUCCESS);
1064
+ process.exit(0);
1065
+ } catch (e) {
1066
+ console.error(Messages.DEV_FAILED);
1067
+ console.error(e);
1068
+ process.exit(1);
1069
+ }
1070
+ }
1071
+ };
1072
+ var runAction = /* @__PURE__ */ __name(async (command, params, directory, stdout = false) => {
795
1073
  try {
796
- const packageManager = PackageManagerFactory.create(packageManagerName);
797
- return await packageManager.build(name, directory, part.entry, part.output, [
798
- "--asset-naming",
799
- "[name].[ext]",
800
- "--target",
801
- part.target === "client" ? "browser" : "node"
802
- ]);
803
- } catch (error3) {
804
- if (error3 && error3.message) {
805
- console.error(ansis.red(error3.message));
1074
+ const packageManager = await PackageManagerFactory.find(directory);
1075
+ await packageManager.runDev(directory, "nf", {}, [command, ...params, "--watch"], !stdout);
1076
+ } catch (error4) {
1077
+ if (error4 && error4.message) {
1078
+ console.error(ansis2.red(error4.message));
806
1079
  }
807
- return false;
808
1080
  }
809
- }, "buildPart");
1081
+ }, "runAction");
810
1082
 
811
1083
  // src/action/actions/generate.action.ts
812
- import * as console2 from "console";
1084
+ import * as console3 from "console";
1085
+ import { join as join3 } from "path";
813
1086
 
814
1087
  // src/lib/schematics/abstract.collection.ts
815
1088
  var AbstractCollection = class {
@@ -899,7 +1172,7 @@ var CollectionFactory = class {
899
1172
  __name(this, "CollectionFactory");
900
1173
  }
901
1174
  static create(collection, directory) {
902
- const schematicRunner = RunnerFactory.create(1 /* SCHEMATIC */);
1175
+ const schematicRunner = RunnerFactory.create(4 /* SCHEMATIC */);
903
1176
  if (collection === "@nanoforge-dev/schematics" /* NANOFORGE */) {
904
1177
  return new NanoforgeCollection(schematicRunner, directory);
905
1178
  } else {
@@ -960,6 +1233,9 @@ var SchematicOption = class {
960
1233
  }
961
1234
  };
962
1235
 
1236
+ // src/action/common/schematics.ts
1237
+ import { watch as watch2 } from "chokidar";
1238
+
963
1239
  // src/action/common/spinner.ts
964
1240
  import ora2 from "ora";
965
1241
  var getSpinner = /* @__PURE__ */ __name((message) => ora2({
@@ -967,16 +1243,22 @@ var getSpinner = /* @__PURE__ */ __name((message) => ora2({
967
1243
  }), "getSpinner");
968
1244
 
969
1245
  // src/action/common/schematics.ts
970
- var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematicName, options) => {
971
- const spinner = getSpinner(Messages.SCHEMATIC_IN_PROGRESS(name));
972
- spinner.start();
973
- await collection.execute(
974
- schematicName,
975
- mapSchematicOptions(options),
976
- void 0,
977
- () => spinner.fail(Messages.SCHEMATIC_FAILED(name))
978
- );
979
- spinner.succeed(Messages.SCHEMATIC_SUCCESS(name));
1246
+ var executeSchematic = /* @__PURE__ */ __name(async (name, collection, schematicName, options, fileToWatch) => {
1247
+ const execute = /* @__PURE__ */ __name(async (watch3 = false) => {
1248
+ const spinner = getSpinner(
1249
+ (watch3 ? Messages.SCHEMATIC_WATCH_IN_PROGRESS : Messages.SCHEMATIC_IN_PROGRESS)(name)
1250
+ );
1251
+ spinner.start();
1252
+ await collection.execute(
1253
+ schematicName,
1254
+ mapSchematicOptions(options),
1255
+ void 0,
1256
+ () => spinner.fail(Messages.SCHEMATIC_FAILED(name))
1257
+ );
1258
+ spinner.succeed(Messages.SCHEMATIC_SUCCESS(name));
1259
+ }, "execute");
1260
+ if (fileToWatch) watch2(fileToWatch).on("change", () => execute(true));
1261
+ return await execute();
980
1262
  }, "executeSchematic");
981
1263
  var mapSchematicOptions = /* @__PURE__ */ __name((inputs) => {
982
1264
  return Object.entries(inputs).reduce((old, [key, value]) => {
@@ -994,18 +1276,25 @@ var GenerateAction = class extends AbstractAction {
994
1276
  __name(this, "GenerateAction");
995
1277
  }
996
1278
  async handle(_args, options) {
997
- console2.info(Messages.NEW_START);
1279
+ console3.info(Messages.GENERATE_START);
1280
+ console3.info();
998
1281
  try {
999
1282
  const directory = getDirectoryInput(options);
1000
1283
  const config2 = await getConfig(options, directory);
1284
+ const watch3 = getWatchInput(options);
1001
1285
  const values = await getSchemaValues(config2);
1002
- await generateFiles(values, directory);
1003
- console2.info();
1004
- console2.info(Messages.NEW_SUCCESS);
1286
+ await generateFiles(values, directory, watch3);
1287
+ console3.info();
1288
+ if (watch3) {
1289
+ console3.info(Messages.GENERATE_WATCH_START);
1290
+ console3.info();
1291
+ return;
1292
+ }
1293
+ console3.info(Messages.GENERATE_SUCCESS);
1005
1294
  process.exit(0);
1006
1295
  } catch (e) {
1007
- console2.error(Messages.NEW_FAILED);
1008
- console2.error(e);
1296
+ console3.error(Messages.GENERATE_FAILED);
1297
+ console3.error(e);
1009
1298
  process.exit(1);
1010
1299
  }
1011
1300
  }
@@ -1019,33 +1308,43 @@ var getSchemaValues = /* @__PURE__ */ __name(async (config2) => {
1019
1308
  initFunctions: config2.initFunctions
1020
1309
  };
1021
1310
  }, "getSchemaValues");
1022
- var generateFiles = /* @__PURE__ */ __name(async (values, directory) => {
1023
- console2.info();
1311
+ var generateFiles = /* @__PURE__ */ __name(async (values, directory, watch3) => {
1024
1312
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1025
- console2.info();
1026
- console2.info(Messages.SCHEMATICS_START);
1027
- console2.info();
1028
- await executeSchematic("Client main file", collection, "part-main", {
1029
- name: values.name,
1030
- part: "client",
1031
- directory: values.directory,
1032
- language: values.language,
1033
- initFunctions: values.initFunctions
1034
- });
1035
- if (values.server) {
1036
- await executeSchematic("Server main file", collection, "part-main", {
1313
+ console3.info(Messages.SCHEMATICS_START);
1314
+ console3.info();
1315
+ await executeSchematic(
1316
+ "Client main file",
1317
+ collection,
1318
+ "part-main",
1319
+ {
1037
1320
  name: values.name,
1038
- part: "server",
1321
+ part: "client",
1039
1322
  directory: values.directory,
1040
1323
  language: values.language,
1041
1324
  initFunctions: values.initFunctions
1042
- });
1325
+ },
1326
+ watch3 ? join3(getCwd(directory), values.directory, ".nanoforge", "client.save.json") : void 0
1327
+ );
1328
+ if (values.server) {
1329
+ await executeSchematic(
1330
+ "Server main file",
1331
+ collection,
1332
+ "part-main",
1333
+ {
1334
+ name: values.name,
1335
+ part: "server",
1336
+ directory: values.directory,
1337
+ language: values.language,
1338
+ initFunctions: values.initFunctions
1339
+ },
1340
+ join3(getCwd(directory), values.directory, ".nanoforge", "server.save.json")
1341
+ );
1043
1342
  }
1044
1343
  }, "generateFiles");
1045
1344
 
1046
1345
  // src/action/actions/install.action.ts
1047
- import * as ansis2 from "ansis";
1048
- import * as process4 from "process";
1346
+ import * as ansis3 from "ansis";
1347
+ import * as process3 from "process";
1049
1348
  var InstallAction = class extends AbstractAction {
1050
1349
  static {
1051
1350
  __name(this, "InstallAction");
@@ -1057,25 +1356,28 @@ var InstallAction = class extends AbstractAction {
1057
1356
  const names = await getInstallNamesInputOrAsk(args);
1058
1357
  const directory = getDirectoryInput(options);
1059
1358
  await installPackages(names, directory);
1060
- process4.exit(0);
1359
+ process3.exit(0);
1061
1360
  } catch (e) {
1062
1361
  console.error(e);
1063
- process4.exit(1);
1362
+ process3.exit(1);
1064
1363
  }
1065
1364
  }
1066
1365
  };
1067
1366
  var installPackages = /* @__PURE__ */ __name(async (names, directory) => {
1068
- const packageManagerName = "bun" /* BUN */;
1069
1367
  try {
1070
- const packageManager = PackageManagerFactory.create(packageManagerName);
1368
+ const packageManager = await PackageManagerFactory.find(directory);
1071
1369
  await packageManager.addProduction(directory, names);
1072
- } catch (error3) {
1073
- if (error3 && error3.message) {
1074
- console.error(ansis2.red(error3.message));
1370
+ } catch (error4) {
1371
+ if (error4 && error4.message) {
1372
+ console.error(ansis3.red(error4.message));
1075
1373
  }
1076
1374
  }
1077
1375
  }, "installPackages");
1078
1376
 
1377
+ // src/action/actions/new.action.ts
1378
+ import * as ansis4 from "ansis";
1379
+ import console4 from "console";
1380
+
1079
1381
  // src/lib/input/inputs/new/init-functions.input.ts
1080
1382
  var getNewInitFunctionsWithDefault = /* @__PURE__ */ __name((inputs) => {
1081
1383
  return getBooleanInputWithDefault(inputs, "initFunctions", false);
@@ -1169,16 +1471,17 @@ var NewAction = class extends AbstractAction {
1169
1471
  __name(this, "NewAction");
1170
1472
  }
1171
1473
  async handle(_args, options) {
1172
- console.info(Messages.NEW_START);
1474
+ console4.info(Messages.NEW_START);
1173
1475
  try {
1174
1476
  const directory = getDirectoryInput(options);
1175
1477
  const values = await getSchemaValues2(options);
1176
1478
  await generateApplicationFiles(values, directory);
1177
- console.info();
1178
- console.info(Messages.NEW_SUCCESS);
1479
+ if (!values.skipInstall) await runInstall(directory, values.packageManager);
1480
+ console4.info();
1481
+ console4.info(Messages.NEW_SUCCESS);
1179
1482
  process.exit(0);
1180
1483
  } catch {
1181
- console.error(Messages.NEW_FAILED);
1484
+ console4.error(Messages.NEW_FAILED);
1182
1485
  process.exit(1);
1183
1486
  }
1184
1487
  }
@@ -1196,11 +1499,11 @@ var getSchemaValues2 = /* @__PURE__ */ __name(async (inputs) => {
1196
1499
  };
1197
1500
  }, "getSchemaValues");
1198
1501
  var generateApplicationFiles = /* @__PURE__ */ __name(async (values, directory) => {
1199
- console.info();
1502
+ console4.info();
1200
1503
  const collection = CollectionFactory.create("@nanoforge-dev/schematics" /* NANOFORGE */, directory);
1201
- console.info();
1202
- console.info(Messages.SCHEMATICS_START);
1203
- console.info();
1504
+ console4.info();
1505
+ console4.info(Messages.SCHEMATICS_START);
1506
+ console4.info();
1204
1507
  await executeSchematic("Application", collection, "application", {
1205
1508
  name: values.name,
1206
1509
  directory: values.directory,
@@ -1245,56 +1548,78 @@ var generateApplicationFiles = /* @__PURE__ */ __name(async (values, directory)
1245
1548
  });
1246
1549
  }
1247
1550
  }, "generateApplicationFiles");
1551
+ var runInstall = /* @__PURE__ */ __name(async (directory, pkgManagerName) => {
1552
+ try {
1553
+ const packageManager = PackageManagerFactory.create(pkgManagerName);
1554
+ await packageManager.install(directory);
1555
+ } catch (error4) {
1556
+ if (error4 && error4.message) {
1557
+ console4.error(ansis4.red(error4.message));
1558
+ }
1559
+ }
1560
+ }, "runInstall");
1248
1561
 
1249
1562
  // src/action/actions/start.action.ts
1250
- import * as ansis3 from "ansis";
1251
- import * as console3 from "console";
1252
- import { join as join3 } from "path";
1563
+ import * as ansis5 from "ansis";
1564
+ import * as console5 from "console";
1565
+ import { join as join4 } from "path";
1253
1566
  var StartAction = class extends AbstractAction {
1254
1567
  static {
1255
1568
  __name(this, "StartAction");
1256
1569
  }
1257
1570
  async handle(_args, options) {
1258
- console3.info(Messages.RUN_START);
1259
- console3.info();
1571
+ console5.info(Messages.RUN_START);
1572
+ console5.info();
1260
1573
  try {
1261
1574
  const directory = getDirectoryInput(options);
1262
1575
  const config2 = await getConfig(options, directory);
1263
1576
  const clientDir = config2.client.runtime.dir;
1264
1577
  const serverDir = config2.server.runtime.dir;
1265
1578
  const clientPort = getStringInputWithDefault(options, "clientPort", config2.client.port);
1579
+ const watch3 = getWatchInput(options);
1266
1580
  await Promise.all([
1267
- config2.server.enable ? this.startServer(directory, serverDir) : void 0,
1268
- this.startClient(clientPort, directory, clientDir)
1581
+ config2.server.enable ? this.startServer(directory, serverDir, watch3) : void 0,
1582
+ this.startClient(clientPort, directory, clientDir, {
1583
+ watch: watch3,
1584
+ serverGameDir: config2.server.enable ? serverDir : void 0
1585
+ })
1269
1586
  ]);
1270
1587
  process.exit(0);
1271
1588
  } catch (e) {
1272
- console3.error(e);
1589
+ console5.error(e);
1273
1590
  process.exit(1);
1274
1591
  }
1275
1592
  }
1276
- async startClient(port, directory, gameDir) {
1593
+ async startClient(port, directory, gameDir, options) {
1277
1594
  const path = getModulePath("@nanoforge-dev/loader-client/package.json", true);
1278
- return runPart("Client", path, {
1595
+ const params = {
1279
1596
  PORT: port,
1280
- GAME_DIR: getCwd(join3(directory, gameDir))
1281
- });
1597
+ GAME_DIR: getCwd(join4(directory, gameDir))
1598
+ };
1599
+ if (options?.watch) {
1600
+ params["WATCH"] = "true";
1601
+ if (options?.serverGameDir) {
1602
+ params["WATCH_SERVER_GAME_DIR"] = getCwd(join4(directory, options.serverGameDir));
1603
+ }
1604
+ }
1605
+ return runPart("Client", path, params);
1282
1606
  }
1283
- startServer(directory, gameDir) {
1607
+ startServer(directory, gameDir, watch3) {
1284
1608
  const path = getModulePath("@nanoforge-dev/loader-server/package.json", true);
1285
- return runPart("Server", path, {
1286
- GAME_DIR: getCwd(join3(directory, gameDir))
1287
- });
1609
+ const params = {
1610
+ GAME_DIR: getCwd(join4(directory, gameDir))
1611
+ };
1612
+ if (watch3) params["WATCH"] = "true";
1613
+ return runPart("Server", path, params);
1288
1614
  }
1289
1615
  };
1290
1616
  var runPart = /* @__PURE__ */ __name(async (part, directory, env2, flags) => {
1291
- const packageManagerName = "bun" /* BUN */;
1292
1617
  try {
1293
- const packageManager = PackageManagerFactory.create(packageManagerName);
1618
+ const packageManager = await PackageManagerFactory.find(directory);
1294
1619
  await packageManager.run(part, directory, "start", env2, flags, true);
1295
- } catch (error3) {
1296
- if (error3 && error3.message) {
1297
- console3.error(ansis3.red(error3.message));
1620
+ } catch (error4) {
1621
+ if (error4 && error4.message) {
1622
+ console5.error(ansis5.red(error4.message));
1298
1623
  }
1299
1624
  }
1300
1625
  }, "runPart");
@@ -1315,12 +1640,30 @@ var BuildCommand = class extends AbstractCommand {
1315
1640
  __name(this, "BuildCommand");
1316
1641
  }
1317
1642
  load(program) {
1318
- program.command("build").description("build your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").action(async (rawOptions) => {
1643
+ program.command("build").description("build your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--client-outDir [clientDirectory]", "specify the output directory of the client").option("--server-outDir [serverDirectory]", "specify the output directory of the server").option("--watch", "build app in watching mode", false).action(async (rawOptions) => {
1319
1644
  const options = /* @__PURE__ */ new Map();
1320
1645
  options.set("directory", { value: rawOptions.directory });
1321
1646
  options.set("config", { value: rawOptions.config });
1322
1647
  options.set("clientDirectory", { value: rawOptions.clientOutDir });
1323
1648
  options.set("serverDirectory", { value: rawOptions.serverOutDir });
1649
+ options.set("watch", { value: rawOptions.watch });
1650
+ const args = /* @__PURE__ */ new Map();
1651
+ await this.action.handle(args, options);
1652
+ });
1653
+ }
1654
+ };
1655
+
1656
+ // src/command/commands/dev.command.ts
1657
+ var DevCommand = class extends AbstractCommand {
1658
+ static {
1659
+ __name(this, "DevCommand");
1660
+ }
1661
+ load(program) {
1662
+ program.command("dev").description("run your game in dev mode").option("-d, --directory [directory]", "specify the directory of your project").option("--generate", "generate app from config", false).action(async (rawOptions) => {
1663
+ const options = /* @__PURE__ */ new Map();
1664
+ options.set("directory", { value: rawOptions.directory });
1665
+ options.set("config", { value: rawOptions.config });
1666
+ options.set("generate", { value: rawOptions.generate });
1324
1667
  const args = /* @__PURE__ */ new Map();
1325
1668
  await this.action.handle(args, options);
1326
1669
  });
@@ -1333,10 +1676,11 @@ var GenerateCommand = class extends AbstractCommand {
1333
1676
  __name(this, "GenerateCommand");
1334
1677
  }
1335
1678
  load(program) {
1336
- program.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").action(async (rawOptions) => {
1679
+ program.command("generate").description("generate nanoforge files from config").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option("--watch", "generate app in watching mode", false).action(async (rawOptions) => {
1337
1680
  const options = /* @__PURE__ */ new Map();
1338
1681
  options.set("directory", { value: rawOptions.directory });
1339
1682
  options.set("config", { value: rawOptions.config });
1683
+ options.set("watch", { value: rawOptions.watch });
1340
1684
  const args = /* @__PURE__ */ new Map();
1341
1685
  await this.action.handle(args, options);
1342
1686
  });
@@ -1391,7 +1735,7 @@ var StartCommand = class extends AbstractCommand {
1391
1735
  program.command("start").description("start your game").option("-d, --directory [directory]", "specify the directory of your project").option("-c, --config [config]", "path to the config file", "nanoforge.config.json").option(
1392
1736
  "-p, --client-port [clientPort]",
1393
1737
  "specify the port of the loader (the website to load the game)"
1394
- ).option("--game-exposure-port [gameExposurePort]", "specify the port of the game exposure").option("--server-port [serverPort]", "specify the port of the server").action(async (rawOptions) => {
1738
+ ).option("--game-exposure-port [gameExposurePort]", "specify the port of the game exposure").option("--server-port [serverPort]", "specify the port of the server").option("--watch", "run app in watching mode", false).action(async (rawOptions) => {
1395
1739
  const options = /* @__PURE__ */ new Map();
1396
1740
  options.set("directory", { value: rawOptions.directory });
1397
1741
  options.set("config", { value: rawOptions.config });
@@ -1400,6 +1744,7 @@ var StartCommand = class extends AbstractCommand {
1400
1744
  value: rawOptions.gameExposurePort
1401
1745
  });
1402
1746
  options.set("serverPort", { value: rawOptions.serverPort });
1747
+ options.set("watch", { value: rawOptions.watch });
1403
1748
  const args = /* @__PURE__ */ new Map();
1404
1749
  await this.action.handle(args, options);
1405
1750
  });
@@ -1413,6 +1758,7 @@ var CommandLoader = class {
1413
1758
  }
1414
1759
  static async load(program) {
1415
1760
  new BuildCommand(new BuildAction()).load(program);
1761
+ new DevCommand(new DevAction()).load(program);
1416
1762
  new GenerateCommand(new GenerateAction()).load(program);
1417
1763
  new InstallCommand(new InstallAction()).load(program);
1418
1764
  new NewCommand(new NewAction()).load(program);
@@ -1422,8 +1768,8 @@ var CommandLoader = class {
1422
1768
  static handleInvalidCommand(program) {
1423
1769
  program.on("command:*", () => {
1424
1770
  console.error(`
1425
- ${Prefixes.ERROR} Invalid command: ${red6`%s`}`, program.args.join(" "));
1426
- console.log(`See ${red6`--help`} for a list of available commands.
1771
+ ${Prefixes.ERROR} Invalid command: ${red8`%s`}`, program.args.join(" "));
1772
+ console.log(`See ${red8`--help`} for a list of available commands.
1427
1773
  `);
1428
1774
  process.exit(1);
1429
1775
  });