@nanoforge-dev/cli 1.5.3 → 1.5.4-beta.2af80f5

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.
@@ -1,4 +1,4 @@
1
- import { bgRgb, bold, green, red, yellow } from "ansis";
1
+ import { bgRgb, bold, cyan, green, red, yellow } from "ansis";
2
2
  import { get } from "node-emoji";
3
3
  import ora from "ora";
4
4
  import { watch } from "chokidar";
@@ -126,12 +126,79 @@ const Prefixes = {
126
126
  //#region src/lib/ui/spinner.ts
127
127
  const getSpinner = (message) => ora({ text: message });
128
128
  //#endregion
129
+ //#region src/lib/utils/errors.ts
130
+ var CLIError = class extends Error {
131
+ suggestion;
132
+ constructor(message, suggestion) {
133
+ super(message);
134
+ this.name = this.constructor.name;
135
+ this.suggestion = suggestion;
136
+ Object.setPrototypeOf(this, new.target.prototype);
137
+ }
138
+ };
139
+ var ConfigNotFoundError = class extends CLIError {
140
+ constructor(configPath) {
141
+ super(`Configuration file not found at path: ${configPath}.`, "Please run 'nf new' or provide a valid --config path.");
142
+ }
143
+ };
144
+ var InvalidCommandArgumentError = class extends CLIError {
145
+ constructor(argName, expected) {
146
+ super(`Invalid argument '${argName}'. Expected: ${expected}.`, "Verify the command syntax using the --help flag.");
147
+ }
148
+ };
149
+ var RegistryAuthenticationError = class extends CLIError {
150
+ constructor() {
151
+ super("You must be logged in to perform this action.", "Run 'nf login' to authenticate.");
152
+ }
153
+ };
154
+ var ManifestError = class extends CLIError {
155
+ constructor(detail) {
156
+ super(`Manifest Error: ${detail}`, "Check your nanoforge.manifest.json file for syntax or formatting errors.");
157
+ }
158
+ };
159
+ var FileSystemError = class extends CLIError {
160
+ constructor(action, targetPath) {
161
+ super(`File System Error [${action}]: ${targetPath}`, "Verify your file permissions and ensure the path exists.");
162
+ }
163
+ };
164
+ var ApiRequestError = class extends CLIError {
165
+ constructor(status, cause) {
166
+ const causeStr = cause && typeof cause === "object" ? JSON.stringify(cause, null, 2) : cause;
167
+ super(`API Request failed (Status ${status})${causeStr ? `\nDetails: ${causeStr}` : ""}`, "Check your network connection, API key, or the registry status.");
168
+ }
169
+ };
170
+ const getErrorString = (error) => {
171
+ const stack = error.stack ? error.stack : error.message;
172
+ const cause = error.cause && typeof error.cause === "object" ? JSON.stringify(error.cause, null, 2) : error.cause;
173
+ return `${stack}${cause ? `\n${cause}` : ""}`;
174
+ };
175
+ const getErrorMessage = (error) => {
176
+ if (error instanceof Error) return getErrorString(error);
177
+ if (typeof error === "string") return error;
178
+ };
179
+ const handleActionError = (context, error) => {
180
+ console.error();
181
+ console.error(red(context));
182
+ if (error instanceof CLIError) {
183
+ console.error(error.message);
184
+ if (error.suggestion) console.info(cyan(`\nšŸ’” Suggestion: ${error.suggestion}`));
185
+ process.exit(1);
186
+ }
187
+ const msg = getErrorMessage(error);
188
+ if (msg) console.error(msg);
189
+ process.exit(1);
190
+ };
191
+ const promptError = (err) => {
192
+ if (err.name === "ExitPromptError") process.exit(1);
193
+ throw err;
194
+ };
195
+ //#endregion
129
196
  //#region src/lib/input/base-inputs.ts
130
197
  const getStringInput = (input, field) => {
131
198
  const value = input.get(field)?.value;
132
199
  if (value === void 0) return void 0;
133
200
  if (typeof value === "string") return value;
134
- throw new Error(`Invalid type for ${field}`);
201
+ throw new InvalidCommandArgumentError(field, "string");
135
202
  };
136
203
  const getStringInputWithDefault = (input, field, defaultValue) => {
137
204
  return getStringInput(input, field) ?? defaultValue;
@@ -140,7 +207,7 @@ const getBooleanInput = (input, field) => {
140
207
  const value = input.get(field)?.value;
141
208
  if (value === void 0) return void 0;
142
209
  if (typeof value === "boolean") return value;
143
- throw new Error(`Invalid type for ${field}`);
210
+ throw new InvalidCommandArgumentError(field, "boolean");
144
211
  };
145
212
  const getBooleanInputWithDefault = (input, field, defaultValue) => {
146
213
  return getBooleanInput(input, field) ?? defaultValue;
@@ -149,7 +216,7 @@ const getArrayInput = (input, field) => {
149
216
  const value = input.get(field)?.value;
150
217
  if (value === void 0) return void 0;
151
218
  if (typeof value === "object" && Array.isArray(value)) return value;
152
- throw new Error(`Invalid type for ${field}`);
219
+ throw new InvalidCommandArgumentError(field, "array");
153
220
  };
154
221
  //#endregion
155
222
  //#region src/lib/input/ask-inputs.ts
@@ -158,7 +225,7 @@ const getInputOrAsk = async (baseInput, askCb, defaultValue) => {
158
225
  const res = await askCb();
159
226
  if (res !== void 0) return res;
160
227
  if (defaultValue !== void 0) return defaultValue;
161
- throw new Error("No input provided");
228
+ throw new CLIError("No input provided. Please provide a valid value.");
162
229
  };
163
230
  //#endregion
164
231
  //#region src/lib/input/inputs/directory.input.ts
@@ -177,28 +244,6 @@ const getEditorInput = (inputs) => {
177
244
  return getBooleanInputWithDefault(inputs, "editor", false);
178
245
  };
179
246
  //#endregion
180
- //#region src/lib/utils/errors.ts
181
- const getErrorMessage = (error) => {
182
- if (error instanceof Error) return getErrorString(error);
183
- if (typeof error === "string") return error;
184
- };
185
- const getErrorString = (error) => {
186
- const stack = error.stack ? error.stack : error.message;
187
- const cause = error.cause && typeof error.cause === "object" ? JSON.stringify(error.cause, null, 2) : error.cause;
188
- return `${stack}${cause ? `\n${cause}` : ""}`;
189
- };
190
- const handleActionError = (context, error) => {
191
- console.error();
192
- console.error(red(context));
193
- const msg = getErrorMessage(error);
194
- if (msg) console.error(msg);
195
- process.exit(1);
196
- };
197
- const promptError = (err) => {
198
- if (err.name === "ExitPromptError") process.exit(1);
199
- throw err;
200
- };
201
- //#endregion
202
247
  //#region src/lib/question/questions/confirm.question.ts
203
248
  const askConfirm = async (question, baseOptions) => {
204
249
  return await confirm({
@@ -290,7 +335,7 @@ const getWatchInput = (inputs) => {
290
335
  const getCreateTypeInput = (inputs) => {
291
336
  const res = getStringInput(inputs, "type");
292
337
  if (res && ["component", "system"].includes(res)) return res;
293
- throw new Error("Invalid type. Please enter 'component' or 'system'.");
338
+ throw new InvalidCommandArgumentError("type", "'component' or 'system'");
294
339
  };
295
340
  //#endregion
296
341
  //#region src/lib/input/inputs/dev/generate.input.ts
@@ -426,7 +471,7 @@ const resolveCLINodeBinaryPath = (name) => {
426
471
  base = join$1(base, "..");
427
472
  }
428
473
  }
429
- throw new Error("Could not find module path");
474
+ throw new FileSystemError("resolve binary", name);
430
475
  };
431
476
  //#endregion
432
477
  //#region src/lib/utils/spinner.ts
@@ -545,7 +590,7 @@ var PackageManager = class {
545
590
  return (await withSpinner(() => this.exec(args, directory), Messages.PACKAGE_MANAGER_INSTALLATION_IN_PROGRESS, Messages.PACKAGE_MANAGER_INSTALLATION_SUCCEED(), Messages.PACKAGE_MANAGER_INSTALLATION_FAILED(this.formatFailCommand(args)))).success;
546
591
  }
547
592
  assertSupports(feature) {
548
- if (!this.commands[feature]) throw new Error(`Package manager "${this.name}" does not support "${feature}"`);
593
+ if (!this.commands[feature]) throw new CLIError(`Package manager "${this.name}" does not support "${feature}"`);
549
594
  }
550
595
  buildRunArgs(script, params, flags, silent) {
551
596
  const args = [...flags, this.commands.run];
@@ -556,7 +601,7 @@ var PackageManager = class {
556
601
  return args.concat(params);
557
602
  }
558
603
  buildRunFileArgs(script, params, flags, silent) {
559
- if (!this.commands.runFile) throw new Error("Package manager does not support runFile");
604
+ if (!this.commands.runFile) throw new CLIError("Package manager does not support runFile");
560
605
  const args = [...flags, this.commands.runFile];
561
606
  if (silent) args.push(this.commands.silentFlag);
562
607
  args.push(script);
@@ -670,7 +715,7 @@ var RunnerFactory = class {
670
715
  try {
671
716
  return getModulePath("@angular-devkit/schematics-cli/bin/schematics.js");
672
717
  } catch {
673
- throw new Error("'schematics' binary path could not be found!");
718
+ throw new CLIError("'schematics' binary path could not be found!");
674
719
  }
675
720
  }
676
721
  };
@@ -762,7 +807,7 @@ const LOCK_FILE_MAP = {
762
807
  var PackageManagerFactory = class {
763
808
  static create(name) {
764
809
  const config = PM_CONFIGS[name];
765
- if (!config) throw new Error(`Package manager ${name} is not managed.`);
810
+ if (!config) throw new CLIError(`Package manager '${name}' is not managed/supported.`);
766
811
  const runner = this.createRunner(name, config.binary);
767
812
  return new PackageManager(name, config.commands, runner);
768
813
  }
@@ -786,7 +831,7 @@ var PackageManagerFactory = class {
786
831
  //#region src/lib/utils/files.ts
787
832
  const copyFiles = (from, to) => {
788
833
  if (!fs.existsSync(from)) return;
789
- if (!fs.existsSync(to)) throw new Error(`Directory ${to} does not exist`);
834
+ if (!fs.existsSync(to)) throw new FileSystemError("directory not found", to);
790
835
  fs.readdirSync(from, { recursive: true }).forEach((file) => {
791
836
  fs.copyFileSync(join$1(from, file.toString()), join$1(to, file.toString()));
792
837
  });
@@ -1013,7 +1058,7 @@ const getConfigPath = (directory, name) => {
1013
1058
  const path = join(directory, n);
1014
1059
  if (existsSync(path)) return path;
1015
1060
  }
1016
- throw new Error(`No config file found in directory: ${directory}`);
1061
+ throw new ConfigNotFoundError(join(directory, CONFIG_FILE_NAME));
1017
1062
  }
1018
1063
  };
1019
1064
  const loadConfig = async (directory, name, noThrow = false) => {
@@ -1025,10 +1070,10 @@ const loadConfig = async (directory, name, noThrow = false) => {
1025
1070
  } catch {
1026
1071
  rawData = noThrow ? CONFIG_DEFAULTS : null;
1027
1072
  }
1028
- if (!rawData) throw new Error(`Not able to read config file : ${path}`);
1073
+ if (!rawData) throw new FileSystemError("read config file", path);
1029
1074
  const data = plainToInstance(Config, rawData, { excludeExtraneousValues: true });
1030
1075
  const errors = await validate(data);
1031
- if (errors.length > 0) throw new Error(`Invalid config :\n${errors.toString().replace(/,/g, "\n")}`);
1076
+ if (errors.length > 0) throw new CLIError(`Invalid config:\n${errors.toString().replace(/,/g, "\n")}`);
1032
1077
  config = data;
1033
1078
  return config;
1034
1079
  };
@@ -1218,7 +1263,7 @@ var NanoforgeCollection = class NanoforgeCollection extends AbstractCollection {
1218
1263
  }
1219
1264
  validate(name) {
1220
1265
  const schematic = NanoforgeCollection.schematics.find((s) => s.name === name || s.alias === name);
1221
- if (schematic === void 0 || schematic === null) throw new Error(`Invalid schematic "${name}". Please, ensure that "${name}" exists in this collection.`);
1266
+ if (schematic === void 0 || schematic === null) throw new CLIError(`Invalid schematic "${name}". Please, ensure that "${name}" exists in this collection.`);
1222
1267
  return schematic.name;
1223
1268
  }
1224
1269
  };
@@ -1228,7 +1273,7 @@ var CollectionFactory = class {
1228
1273
  static create(collection, directory) {
1229
1274
  const schematicRunner = RunnerFactory.createSchematic();
1230
1275
  if (collection === "@nanoforge-dev/schematics") return new NanoforgeCollection(schematicRunner, directory);
1231
- throw new Error(`Unknown collection: ${collection}`);
1276
+ throw new CLIError(`Unknown collection: ${collection}`);
1232
1277
  }
1233
1278
  };
1234
1279
  //#endregion
@@ -1322,20 +1367,34 @@ var DevAction = class extends AbstractAction {
1322
1367
  async handle(_args, options) {
1323
1368
  const directory = getDirectoryInput(options);
1324
1369
  const generate = getDevGenerateInput(options);
1325
- const tasks = this.buildTaskList(directory, generate);
1370
+ const editor = getEditorInput(options);
1371
+ const tasks = this.buildTaskList(directory, generate, editor);
1326
1372
  await Promise.all(tasks);
1327
1373
  return { keepAlive: true };
1328
1374
  }
1329
- buildTaskList(directory, generate) {
1375
+ buildTaskList(directory, generate, editor) {
1330
1376
  const tasks = [];
1331
- if (generate) tasks.push(this.runSubCommand("generate", directory, { silent: true }));
1332
- tasks.push(this.runSubCommand("build", directory, { silent: true }));
1377
+ const extraFlags = editor ? ["--editor"] : [];
1378
+ if (generate) tasks.push(this.runSubCommand("generate", directory, {
1379
+ silent: true,
1380
+ extraFlags
1381
+ }));
1382
+ tasks.push(this.runSubCommand("build", directory, {
1383
+ silent: true,
1384
+ extraFlags
1385
+ }));
1333
1386
  tasks.push(this.runSubCommand("start", directory, { silent: false }));
1334
1387
  return tasks;
1335
1388
  }
1336
1389
  async runSubCommand(command, directory, options) {
1337
1390
  await runSafe(async () => {
1338
- await (await PackageManagerFactory.find(directory)).runDev(directory, "nf", {}, [command, "--watch"], options.silent);
1391
+ const packageManager = await PackageManagerFactory.find(directory);
1392
+ const args = [
1393
+ command,
1394
+ "--watch",
1395
+ ...options.extraFlags ?? []
1396
+ ];
1397
+ await packageManager.runDev(directory, "nf", {}, args, options.silent);
1339
1398
  });
1340
1399
  }
1341
1400
  };
@@ -1563,27 +1622,24 @@ var Repository = class {
1563
1622
  async runRequest(request, path, options) {
1564
1623
  const res = await this._client[request](path, options);
1565
1624
  const data = await res.json();
1566
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: data["error"] });
1625
+ if (!res.ok) throw new ApiRequestError(res.status, data["error"]);
1567
1626
  return data;
1568
1627
  }
1569
1628
  async runFileRequest(request, path, options) {
1570
1629
  const res = await this._client[request](path, options);
1571
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: (await res.json())["error"] });
1630
+ if (!res.ok) throw new ApiRequestError(res.status, (await res.json())["error"]);
1572
1631
  return await res.blob();
1573
1632
  }
1574
1633
  async runRequestBody(request, path, body, options) {
1575
1634
  const res = await this._client[request](path, body === void 0 ? void 0 : body instanceof FormData ? body : JSON.stringify(body), options);
1576
1635
  const data = await res.json();
1577
- if (!res.ok) throw new Error(`Request failed with status code ${res.status}`, { cause: data["error"] });
1636
+ if (!res.ok) throw new ApiRequestError(res.status, data["error"]);
1578
1637
  return data;
1579
1638
  }
1580
1639
  };
1581
1640
  new Repository(new HttpClient("https://api.nanoforge.eu"));
1582
1641
  const withAuth = (apiKey, force = false, headers = { "Content-Type": "application/json" }) => {
1583
- if (!apiKey && force) {
1584
- console.error("No registry key found. Please use `nf login` to login");
1585
- throw new Error("No apikey found. Please use `nf login` to login");
1586
- }
1642
+ if (!apiKey && force) throw new RegistryAuthenticationError();
1587
1643
  return new Repository(new HttpClient("https://api.nanoforge.eu", { headers: {
1588
1644
  Authorization: apiKey,
1589
1645
  ...headers
@@ -1659,12 +1715,12 @@ var Registry = class {
1659
1715
  }
1660
1716
  static _getPackageFile(filename, dir) {
1661
1717
  const path = join$1(getCwd(dir ?? "."), filename);
1662
- if (!fs.existsSync(path)) throw new Error("Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!");
1718
+ if (!fs.existsSync(path)) throw new CLIError("Package not found, please specify path in the nanoforge.manifest.json : `publish.paths.package`!");
1663
1719
  try {
1664
1720
  fs.accessSync(path, fs.constants.R_OK);
1665
1721
  return fs.openAsBlob(path);
1666
1722
  } catch {
1667
- throw new Error("Cannot read package file, please verify your file permissions!");
1723
+ throw new CLIError("Cannot read package file, please verify your file permissions!");
1668
1724
  }
1669
1725
  }
1670
1726
  };
@@ -1971,7 +2027,7 @@ const getManifestPath = (directory) => {
1971
2027
  const path = join(directory, n);
1972
2028
  if (existsSync(path)) return path;
1973
2029
  }
1974
- throw new Error(`No manifest file found in directory: ${directory}`);
2030
+ throw new ManifestError(`No manifest file found in directory: ${directory}`);
1975
2031
  };
1976
2032
  const loadManifest = async (directory) => {
1977
2033
  let rawData;
@@ -1981,10 +2037,10 @@ const loadManifest = async (directory) => {
1981
2037
  } catch {
1982
2038
  rawData = null;
1983
2039
  }
1984
- if (!rawData) throw new Error(`Not able to read manifest file : ${path}`);
2040
+ if (!rawData) throw new ManifestError(`Unable to read or parse file at ${path}`);
1985
2041
  const data = plainToInstance(Manifest, rawData, { excludeExtraneousValues: true });
1986
2042
  const errors = await validate(data);
1987
- if (errors.length > 0) throw new Error(`Invalid manifest\n${errors.toString().replace(/,/g, "\n")}`);
2043
+ if (errors.length > 0) throw new ManifestError(`Validation failed\n${errors.toString()}`);
1988
2044
  return data;
1989
2045
  };
1990
2046
  //#endregion
@@ -2027,8 +2083,8 @@ var StartAction = class extends AbstractAction {
2027
2083
  const cert = getStringInput(options, "cert");
2028
2084
  const key = getStringInput(options, "key");
2029
2085
  if (!cert && !key) return void 0;
2030
- if (!cert) throw new Error("No cert entered for SSL. Please enter a key with --cert.");
2031
- if (!key) throw new Error("No key entered for SSL. Please enter a key with --key.");
2086
+ if (!cert) throw new CLIError("No cert entered for SSL. Please enter a cert with --cert.");
2087
+ if (!key) throw new CLIError("No key entered for SSL. Please enter a key with --key.");
2032
2088
  return {
2033
2089
  cert,
2034
2090
  key
@@ -2173,11 +2229,12 @@ var CreateCommand = class extends AbstractCommand {
2173
2229
  //#region src/command/commands/dev.command.ts
2174
2230
  var DevCommand = class extends AbstractCommand {
2175
2231
  load(program) {
2176
- program.command("dev").description("run your game in dev mode").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).action(async (rawOptions) => {
2232
+ program.command("dev").description("run your game in dev mode").option("-d, --directory <directory>", "specify the working directory of the command").option("-c, --config <config>", "path to the config file", CONFIG_FILE_NAME).option("--generate", "generate app from config", false).option("-e, --editor", "run the editor", false).action(async (rawOptions) => {
2177
2233
  const options = AbstractCommand.mapToInput({
2178
2234
  directory: rawOptions.directory,
2179
2235
  config: rawOptions.config,
2180
- generate: rawOptions.generate
2236
+ generate: rawOptions.generate,
2237
+ editor: rawOptions.editor
2181
2238
  });
2182
2239
  await this.action.run(/* @__PURE__ */ new Map(), options);
2183
2240
  });