create-react-router 0.0.0-experimental-abd9fc79b → 0.0.0-experimental-2a01b6fd8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/cli.js +104 -61
  3. package/package.json +1 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # `create-react-router`
2
2
 
3
+ ## v8.3.0
4
+
5
+ ### Patch Changes
6
+
7
+ - _No changes_
8
+
9
+ ## v8.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - Detect `nub` as a supported package manager when creating new projects ([#15276](https://github.com/remix-run/react-router/pull/15276))
14
+
15
+ ## v8.1.0
16
+
17
+ ### Minor Changes
18
+
19
+ - Add a default-on CLI option to include the official React Router agent skill in generated projects ([#15213](https://github.com/remix-run/react-router/pull/15213))
20
+ - New projects include `.agents/skills/react-router` by default when running with `--yes` or in non-interactive shells
21
+ - Interactive runs prompt to include the skill, defaulting to yes
22
+ - Use `--no-agent-skills` to skip copying the skill
23
+
24
+ ### Patch Changes
25
+
26
+ - Use Node's built-in utilities for CLI argument parsing, ANSI-stripping, and child process execution to remove the `arg`, `strip-ansi`, and `execa` dependencies ([#15231](https://github.com/remix-run/react-router/pull/15231))
27
+
3
28
  ## v8.0.1
4
29
 
5
30
  ### Patch Changes
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * create-react-router v0.0.0-experimental-abd9fc79b
3
+ * create-react-router v0.0.0-experimental-2a01b6fd8
4
4
  *
5
5
  * Copyright (c) Remix Software Inc.
6
6
  *
@@ -10,14 +10,13 @@
10
10
  * @license MIT
11
11
  */
12
12
  import process from "node:process";
13
+ import { spawn } from "node:child_process";
13
14
  import fs, { existsSync } from "node:fs";
14
15
  import { cp, readFile, readdir, realpath, writeFile } from "node:fs/promises";
15
16
  import os from "node:os";
16
17
  import path from "node:path";
17
18
  import url, { fileURLToPath } from "node:url";
18
- import stripAnsi from "strip-ansi";
19
- import { execa } from "execa";
20
- import arg from "arg";
19
+ import { parseArgs, promisify, stripVTControlCharacters } from "node:util";
21
20
  import * as semver from "semver";
22
21
  import sortPackageJSON from "sort-package-json";
23
22
  import { beep, cursor, erase } from "sisteransi";
@@ -25,7 +24,6 @@ import EventEmitter from "node:events";
25
24
  import readline from "node:readline";
26
25
  import pc from "picocolors";
27
26
  import stream from "node:stream";
28
- import { promisify } from "node:util";
29
27
  import gunzip from "gunzip-maybe";
30
28
  import tar from "tar-fs";
31
29
  //#region utils.ts
@@ -155,7 +153,7 @@ function isUrl(value) {
155
153
  try {
156
154
  new URL(value);
157
155
  return true;
158
- } catch (e) {
156
+ } catch {
159
157
  return false;
160
158
  }
161
159
  }
@@ -250,7 +248,7 @@ var Prompt = class extends EventEmitter {
250
248
  let a = action(key, isSelect);
251
249
  if (a === false) try {
252
250
  this._(str, key);
253
- } catch (e) {}
251
+ } catch {}
254
252
  else if (typeof this[a] === "function") this[a](key);
255
253
  };
256
254
  this.close = () => {
@@ -887,7 +885,7 @@ async function prompt(questions, opts = {}) {
887
885
  }, question));
888
886
  answers[name] = answer;
889
887
  quit = await onSubmit(question, answer, answers);
890
- } catch (e) {
888
+ } catch {
891
889
  quit = !await onCancel(question, answers);
892
890
  }
893
891
  if (quit) return answers;
@@ -1064,7 +1062,7 @@ async function copyTemplate(template, destPath, options) {
1064
1062
  function isLocalFilePath(input) {
1065
1063
  try {
1066
1064
  return input.startsWith("file://") || fs.existsSync(path.isAbsolute(input) ? input : path.resolve(process.cwd(), input));
1067
- } catch (e) {
1065
+ } catch {
1068
1066
  return false;
1069
1067
  }
1070
1068
  }
@@ -1158,7 +1156,7 @@ async function downloadAndExtractTarball(downloadPath, tarballUrl, { token, file
1158
1156
  return header.name === "__IGNORE__";
1159
1157
  }
1160
1158
  }));
1161
- } catch (e) {
1159
+ } catch {
1162
1160
  throw new CopyTemplateError(`There was a problem extracting the file from the provided template. Template URL: \`${tarballUrl}\` Destination directory: \`${downloadPath}\``);
1163
1161
  }
1164
1162
  if (filePath && !filePathHasFiles) throw new CopyTemplateError(`The path "${filePath}" was not found in this ${isGithubUrl ? "GitHub repo." : "tarball."}`);
@@ -1187,7 +1185,7 @@ function isValidGithubRepoUrl(input) {
1187
1185
  let url = new URL(input);
1188
1186
  let pathSegments = url.pathname.slice(1).split("/");
1189
1187
  return url.protocol === "https:" && url.hostname === "github.com" && pathSegments.length >= 2 && (pathSegments.length > 2 ? pathSegments[2] === "tree" && pathSegments.length >= 4 : true);
1190
- } catch (e) {
1188
+ } catch {
1191
1189
  return false;
1192
1190
  }
1193
1191
  }
@@ -1239,7 +1237,7 @@ var CopyTemplateError = class extends Error {
1239
1237
  };
1240
1238
  //#endregion
1241
1239
  //#region package.json
1242
- var version = "0.0.0-experimental-abd9fc79b";
1240
+ var version = "0.0.0-experimental-2a01b6fd8";
1243
1241
  //#endregion
1244
1242
  //#region index.ts
1245
1243
  const currentFileDir = path.dirname(fileURLToPath(import.meta.url));
@@ -1276,36 +1274,48 @@ async function createReactRouter(argv) {
1276
1274
  }
1277
1275
  }
1278
1276
  async function getContext(argv) {
1279
- let flags = arg({
1280
- "--debug": Boolean,
1281
- "--react-router-version": String,
1282
- "-v": "--react-router-version",
1283
- "--template": String,
1284
- "--token": String,
1285
- "--yes": Boolean,
1286
- "-y": "--yes",
1287
- "--install": Boolean,
1288
- "--no-install": Boolean,
1289
- "--package-manager": String,
1290
- "--show-install-output": Boolean,
1291
- "--agent-skills": Boolean,
1292
- "--with-agent-skills": "--agent-skills",
1293
- "--no-agent-skills": Boolean,
1294
- "--git-init": Boolean,
1295
- "--no-git-init": Boolean,
1296
- "--help": Boolean,
1297
- "-h": "--help",
1298
- "--version": Boolean,
1299
- "--V": "--version",
1300
- "--no-color": Boolean,
1301
- "--no-motion": Boolean,
1302
- "--overwrite": Boolean
1303
- }, {
1304
- argv,
1305
- permissive: true
1277
+ let { values, positionals } = parseArgs({
1278
+ args: argv,
1279
+ allowPositionals: true,
1280
+ strict: false,
1281
+ options: {
1282
+ "agent-skills": { type: "boolean" },
1283
+ debug: { type: "boolean" },
1284
+ "git-init": { type: "boolean" },
1285
+ help: {
1286
+ type: "boolean",
1287
+ short: "h"
1288
+ },
1289
+ install: { type: "boolean" },
1290
+ "no-agent-skills": { type: "boolean" },
1291
+ "no-color": { type: "boolean" },
1292
+ "no-git-init": { type: "boolean" },
1293
+ "no-install": { type: "boolean" },
1294
+ "no-motion": { type: "boolean" },
1295
+ overwrite: { type: "boolean" },
1296
+ "package-manager": { type: "string" },
1297
+ "react-router-version": {
1298
+ type: "string",
1299
+ short: "v"
1300
+ },
1301
+ "show-install-output": { type: "boolean" },
1302
+ template: { type: "string" },
1303
+ token: { type: "string" },
1304
+ version: {
1305
+ type: "boolean",
1306
+ short: "V"
1307
+ },
1308
+ yes: {
1309
+ type: "boolean",
1310
+ short: "y"
1311
+ }
1312
+ }
1306
1313
  });
1307
- let { "--debug": debug = false, "--help": help = false, "--react-router-version": selectedReactRouterVersion, "--template": template, "--token": token, "--install": install, "--no-install": noInstall, "--package-manager": pkgManager, "--show-install-output": showInstallOutput = false, "--agent-skills": agentSkills, "--no-agent-skills": noAgentSkills, "--git-init": git, "--no-git-init": noGit, "--no-motion": noMotion, "--yes": yes, "--version": versionRequested, "--overwrite": overwrite } = flags;
1308
- let cwd = flags["_"][0];
1314
+ let getBooleanArg = (value) => typeof value === "boolean" ? value : void 0;
1315
+ let getStringArg = (value) => typeof value === "string" ? value : void 0;
1316
+ let selectedReactRouterVersion = getStringArg(values["react-router-version"]);
1317
+ let yes = getBooleanArg(values.yes);
1318
+ let cwd = positionals[0];
1309
1319
  let interactive = isInteractive();
1310
1320
  let projectName = cwd;
1311
1321
  if (!interactive) yes = true;
@@ -1317,22 +1327,22 @@ async function getContext(argv) {
1317
1327
  return {
1318
1328
  tempDir: path.join(await realpath(os.tmpdir()), `create-react-router--${Math.random().toString(36).substr(2, 8)}`),
1319
1329
  cwd,
1320
- overwrite,
1330
+ overwrite: getBooleanArg(values.overwrite),
1321
1331
  interactive,
1322
- debug,
1323
- agentSkills: agentSkills ?? (noAgentSkills ? false : yes),
1324
- git: git ?? (noGit ? false : yes),
1325
- help,
1326
- install: install ?? (noInstall ? false : yes),
1327
- showInstallOutput,
1328
- noMotion,
1329
- pkgManager: validatePackageManager(pkgManager ?? (process.env.npm_config_user_agent ?? "npm").split("/")[0]),
1332
+ debug: getBooleanArg(values.debug) ?? false,
1333
+ agentSkills: getBooleanArg(values["agent-skills"]) ?? (getBooleanArg(values["no-agent-skills"]) ? false : yes),
1334
+ git: getBooleanArg(values["git-init"]) ?? (getBooleanArg(values["no-git-init"]) ? false : yes),
1335
+ help: getBooleanArg(values.help) ?? false,
1336
+ install: getBooleanArg(values.install) ?? (getBooleanArg(values["no-install"]) ? false : yes),
1337
+ showInstallOutput: getBooleanArg(values["show-install-output"]) ?? false,
1338
+ noMotion: getBooleanArg(values["no-motion"]),
1339
+ pkgManager: validatePackageManager(getStringArg(values["package-manager"]) ?? detectPackageManager() ?? "npm"),
1330
1340
  projectName,
1331
1341
  prompt,
1332
1342
  reactRouterVersion: selectedReactRouterVersion || version,
1333
- template,
1334
- token,
1335
- versionRequested
1343
+ template: getStringArg(values.template),
1344
+ token: getStringArg(values.token),
1345
+ versionRequested: getBooleanArg(values.version)
1336
1346
  };
1337
1347
  }
1338
1348
  async function introStep(ctx) {
@@ -1424,7 +1434,7 @@ async function agentSkillsQuestionStep(ctx) {
1424
1434
  let { agentSkills = true } = await ctx.prompt({
1425
1435
  name: "agentSkills",
1426
1436
  type: "confirm",
1427
- label: title("agents"),
1437
+ label: title("skill"),
1428
1438
  message: "Include the React Router agent skill?",
1429
1439
  hint: "recommended",
1430
1440
  initial: true
@@ -1584,9 +1594,9 @@ async function gitInitStep(ctx) {
1584
1594
  };
1585
1595
  let commitMsg = "Initial commit from create-react-router";
1586
1596
  try {
1587
- await execa("git", ["init"], options);
1588
- await execa("git", ["add", "."], options);
1589
- await execa("git", [
1597
+ await runCommand("git", ["init"], options);
1598
+ await runCommand("git", ["add", "."], options);
1599
+ await runCommand("git", [
1590
1600
  "commit",
1591
1601
  "-m",
1592
1602
  commitMsg
@@ -1608,12 +1618,12 @@ async function doneStep(ctx) {
1608
1618
  await sleep(100);
1609
1619
  if (projectDir !== "") {
1610
1620
  let enter = [`\n${prefix}Enter your project directory using`, color.cyan(`cd .${path.sep}${projectDir}`)];
1611
- let len = enter[0].length + stripAnsi(enter[1]).length;
1621
+ let len = enter[0].length + stripVTControlCharacters(enter[1]).length;
1612
1622
  log(enter.join(len > max ? "\n" + prefix : " "));
1613
1623
  }
1614
1624
  log(`${prefix}Check out ${color.bold("README.md")} for development and deploy instructions.`);
1615
1625
  await sleep(100);
1616
- log(`\n${prefix}Join the community at ${color.cyan(`https://rmx.as/discord`)}\n`);
1626
+ log(`\n${prefix}Join the community at ${color.cyan(`https://remix.run/discord`)}\n`);
1617
1627
  await sleep(200);
1618
1628
  }
1619
1629
  const validPackageManagers = [
@@ -1621,14 +1631,37 @@ const validPackageManagers = [
1621
1631
  "yarn",
1622
1632
  "pnpm",
1623
1633
  "bun",
1624
- "deno"
1634
+ "deno",
1635
+ "nub"
1625
1636
  ];
1626
1637
  function validatePackageManager(pkgManager) {
1627
1638
  return validPackageManagers.find((name) => pkgManager === name) ?? "npm";
1628
1639
  }
1640
+ /**
1641
+ * Determine which package manager the user prefers.
1642
+ *
1643
+ * npm, pnpm, Yarn, Bun, Deno, and nub set the user agent environment variable
1644
+ * that can be used to determine which package manager ran the command.
1645
+ */
1646
+ function detectPackageManager() {
1647
+ let { npm_config_user_agent } = process.env;
1648
+ if (!npm_config_user_agent) return void 0;
1649
+ try {
1650
+ let pkgManager = npm_config_user_agent.split("/")[0];
1651
+ if (pkgManager === "npm") return "npm";
1652
+ if (pkgManager === "pnpm") return "pnpm";
1653
+ if (pkgManager === "yarn") return "yarn";
1654
+ if (pkgManager === "bun") return "bun";
1655
+ if (pkgManager === "deno") return "deno";
1656
+ if (pkgManager === "nub") return "nub";
1657
+ return;
1658
+ } catch {
1659
+ return;
1660
+ }
1661
+ }
1629
1662
  async function installDependencies({ pkgManager, cwd, showInstallOutput }) {
1630
1663
  try {
1631
- await execa(pkgManager, ["install"], {
1664
+ await runCommand(pkgManager, ["install"], {
1632
1665
  cwd,
1633
1666
  stdio: showInstallOutput ? "inherit" : "ignore"
1634
1667
  });
@@ -1637,6 +1670,16 @@ async function installDependencies({ pkgManager, cwd, showInstallOutput }) {
1637
1670
  throw err;
1638
1671
  }
1639
1672
  }
1673
+ function runCommand(command, args, options) {
1674
+ return new Promise((resolve, reject) => {
1675
+ let child = spawn(command, args, options);
1676
+ child.on("error", reject);
1677
+ child.on("exit", (code, signal) => {
1678
+ if (code === 0) resolve();
1679
+ else reject(/* @__PURE__ */ new Error(signal ? `${command} exited with signal ${signal}` : `${command} exited with code ${code}`));
1680
+ });
1681
+ });
1682
+ }
1640
1683
  async function updatePackageJSON(ctx) {
1641
1684
  let packageJSONPath = path.join(ctx.cwd, "package.json");
1642
1685
  if (!existsSync(packageJSONPath)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-react-router",
3
3
  "type": "module",
4
- "version": "0.0.0-experimental-abd9fc79b",
4
+ "version": "0.0.0-experimental-2a01b6fd8",
5
5
  "description": "Create a new React Router app",
6
6
  "homepage": "https://reactrouter.com",
7
7
  "bugs": {
@@ -34,15 +34,12 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "arg": "^5.0.1",
38
- "execa": "9.6.1",
39
37
  "gunzip-maybe": "^1.4.2",
40
38
  "log-update": "^8.0.0",
41
39
  "picocolors": "^1.1.1",
42
40
  "semver": "^7.8.1",
43
41
  "sisteransi": "^1.0.5",
44
42
  "sort-package-json": "^3.6.1",
45
- "strip-ansi": "^7.2.0",
46
43
  "tar-fs": "^3.1.2"
47
44
  },
48
45
  "devDependencies": {