expo-desktop 0.1.20 → 0.1.24

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.
@@ -224,9 +224,6 @@ async function renameCppAppPathsAsync(windowsRoot, filesafeName) {
224
224
  });
225
225
  const chosen = candidates[0];
226
226
  const newRelWin = cppAppRelativePathTransform(chosen.rel, filesafeName);
227
- if (newRelWin === chosen.rel) {
228
- throw new Error(`Windows cpp-app rename: expected path containing MyApp to change: "${chosen.rel}"`);
229
- }
230
227
  const newAbs = path.join(windowsRoot, newRelWin);
231
228
  if (newAbs === chosen.abs) {
232
229
  continue;
@@ -1,14 +1,15 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import fs from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { env } from "node:process";
4
+ import process from "node:process";
5
5
  import readline from "node:readline";
6
6
  import { stripVTControlCharacters } from "node:util";
7
7
  /**
8
8
  * Clack {@link Task} that runs a subprocess; piped stdout/stderr lines are sent
9
- * through the task `message` callback (not `log.message`). Lines are also kept in
10
- * an interleaved buffer; on failure they are written under {@link debugLogDir} or
11
- * {@link SpawnOptions.cwd} or the current working directory.
9
+ * through the task `message` callback (not `log.message`). Lines are also kept
10
+ * in an interleaved buffer; on failure they are written under
11
+ * {@link debugLogDir} or {@link SpawnOptions.cwd} or the current working
12
+ * directory.
12
13
  */
13
14
  export function promisifiedSpawnTask({ title, command, args, options = {}, debugLogDir, }) {
14
15
  return {
@@ -16,7 +17,16 @@ export function promisifiedSpawnTask({ title, command, args, options = {}, debug
16
17
  task: (message) => runPromisifiedSpawn({
17
18
  command,
18
19
  args,
19
- options,
20
+ options: {
21
+ // On Windows, Volta-managed package managers are spawned via .cmd
22
+ // shims which require shell interpretation. Although I've been having
23
+ // luck with `shell: false` with Volta-managed package managers on
24
+ // macOS, I'd rather just go with one consistent approach across all
25
+ // platforms, and `shell: true` will tend to reduce surprises.
26
+ // https://github.com/shirakaba/expo-desktop/issues/4
27
+ shell: true,
28
+ ...options,
29
+ },
20
30
  logLine: message,
21
31
  ...(debugLogDir !== undefined ? { debugLogDir } : {}),
22
32
  }),
@@ -29,7 +39,7 @@ function runPromisifiedSpawn({ command, args, options, logLine, debugLogDir, })
29
39
  stdio: stdioEffective,
30
40
  env: envWithForcedColorIfPiped({ ...options, stdio: stdioEffective }),
31
41
  };
32
- const cp = spawn(command, args, spawnOptions);
42
+ const cp = spawn(`${command} ${args.join(" ")}`, spawnOptions);
33
43
  /** Interleaved stdout/stderr lines in arrival order (tagged for readability). */
34
44
  const lineBuffer = [];
35
45
  const pushLine = (stream, line) => {
@@ -129,7 +139,7 @@ function envWithForcedColorIfPiped(options) {
129
139
  const stdoutMode = Array.isArray(stdio) ? stdio.at(1) : stdio;
130
140
  const stderrMode = Array.isArray(stdio) ? stdio.at(2) : stdio;
131
141
  const capturesOutput = stdoutMode !== "inherit" || stderrMode !== "inherit";
132
- const base = { ...env, ...options?.env };
142
+ const base = { ...process.env, ...options?.env };
133
143
  if (!capturesOutput || base.NO_COLOR !== undefined) {
134
144
  return base;
135
145
  }
@@ -0,0 +1,34 @@
1
+ import { Shescape } from "shescape";
2
+ const defaultShell = Symbol("Default shell");
3
+ const shescapes = {};
4
+ export function getShescape(shell) {
5
+ const resolvedShell = shell ?? defaultShell;
6
+ if (shescapes[resolvedShell]) {
7
+ return shescapes[resolvedShell];
8
+ }
9
+ const shescapeOptions = {};
10
+ if (typeof resolvedShell === "string") {
11
+ shescapeOptions.shell = resolvedShell;
12
+ }
13
+ let shescape;
14
+ try {
15
+ shescape = new Shescape(shescapeOptions);
16
+ }
17
+ catch (cause) {
18
+ if (!(cause instanceof Error) || cause.message !== "Shescape does not support the shell sh") {
19
+ throw new Error("Unable to spawn child process due to error being thrown when constructing Shescape instance", { cause });
20
+ }
21
+ // Can't escape for the meta-shell `/bin/sh`. Let's try falling back to a
22
+ // typical Unix shell and hoping for the best.
23
+ // https://github.com/ericcornelissen/shescape/issues/2009
24
+ try {
25
+ shescapeOptions.shell = process.platform === "darwin" ? "zsh" : "bash";
26
+ shescape = new Shescape(shescapeOptions);
27
+ }
28
+ catch (cause) {
29
+ throw new Error("Unable to spawn child process due to error being thrown when constructing fallback Shescape instance", { cause });
30
+ }
31
+ }
32
+ shescapes[resolvedShell] = shescape;
33
+ return shescape;
34
+ }
@@ -14,6 +14,7 @@ import { pathToFileURL } from "node:url";
14
14
  import { applyWindowsCppAppTemplateAsync } from "./apply-windows-cpp-app-template.js";
15
15
  import { promisifiedSpawnTask } from "./child-process.js";
16
16
  import { getTemplateFilesToRenameAsync, renameTemplateAppNameAsync, } from "./rename-template-app-name.js";
17
+ import { getShescape } from "./shescape.js";
17
18
  export async function applySelectedTemplatesAsync({ projectRoot, selection, enabledPlatforms, name, respectTemplateConfig, }) {
18
19
  const descriptors = getOrderedTemplateDescriptors(selection, enabledPlatforms);
19
20
  if (!descriptors.length) {
@@ -112,6 +113,8 @@ function parseTemplateSource(template) {
112
113
  return { type: "npm", spec: template };
113
114
  }
114
115
  async function prepareTemplateSourceAsync(taskTitle, source) {
116
+ // We make sure there are no spaces in the path so that we don't need to
117
+ // quote/escape the shell command.
115
118
  const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "expo-desktop-template-"));
116
119
  const archivePath = path.join(tempRoot, "template.tgz");
117
120
  switch (source.type) {
@@ -119,6 +122,8 @@ async function prepareTemplateSourceAsync(taskTitle, source) {
119
122
  await fs.copyFile(source.path, archivePath);
120
123
  break;
121
124
  case "github": {
125
+ // Don't think it's possible to have spaces in the owner/repo/ref, so no
126
+ // percent-encoding or quoting needed.
122
127
  const tarballUrl = `https://codeload.github.com/${source.owner}/${source.repo}/tar.gz/${source.ref}`;
123
128
  const response = await fetch(tarballUrl);
124
129
  if (!response.ok || !response.body) {
@@ -129,11 +134,12 @@ async function prepareTemplateSourceAsync(taskTitle, source) {
129
134
  break;
130
135
  }
131
136
  case "npm": {
137
+ const shescape = getShescape();
132
138
  await tasks([
133
139
  promisifiedSpawnTask({
134
140
  title: `npm pack (${source.spec})`,
135
141
  command: "npm",
136
- args: ["pack", source.spec, "--silent"],
142
+ args: ["pack", shescape.quote(source.spec), "--silent"],
137
143
  options: { cwd: tempRoot },
138
144
  }),
139
145
  ]);
@@ -272,6 +272,9 @@ async function updatePackageJson({ localDev, name, projectPath, task, versions,
272
272
  ["expo-desktop-stubs"]: `^${versions.expoMajor}.0.0`,
273
273
  };
274
274
  for (const [key, value] of Object.entries(monorepoDeps)) {
275
+ // TODO: Try replacing this `localDev` logic with `linkWorkspacePackages`:
276
+ // - https://pnpm.io/workspaces#linkworkspacepackages
277
+ // - https://pnpm.io/workspaces#workspace-protocol-workspace
275
278
  packageJson.dependencies[key] = localDev ? `file:../../${key}` : value;
276
279
  }
277
280
  packageJson.dependencies["react-native-macos"] = versions.macos;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-desktop",
3
- "version": "0.1.20",
3
+ "version": "0.1.24",
4
4
  "description": "Best-effort desktop support for Expo",
5
5
  "keywords": [
6
6
  "android",
@@ -37,12 +37,13 @@
37
37
  "@clack/prompts": "^1.2.0",
38
38
  "arktype": "^2.2.0",
39
39
  "citty": "^0.2.2",
40
+ "expo-desktop-config-plugins": "^1.1.22",
41
+ "expo-desktop-prebuild-config": "^1.0.11",
40
42
  "glob": "^10.5.0",
41
43
  "kleur": "^4.1.5",
42
44
  "mustache": "^4.2.0",
43
- "toml": "^4.1.1",
44
- "expo-desktop-config-plugins": "1.1.20",
45
- "expo-desktop-prebuild-config": "1.0.9"
45
+ "shescape": "^2.1.12",
46
+ "toml": "^4.1.1"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@expo/config": "^12.0.13",