@wp-playground/cli 3.0.18 → 3.0.20

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/README.md CHANGED
@@ -91,7 +91,7 @@ The `server` command supports the following optional arguments:
91
91
  - `--blueprint=<path>`: The path to a JSON Blueprint file to execute.
92
92
  - `--blueprint-may-read-adjacent-files`: Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.
93
93
  - `--login`: Automatically log the user in as an administrator.
94
- - `--skip-wordpress-setup`: Do not download or install WordPress. Useful if you are mounting a full WordPress directory.
94
+ - `--wordpress-install-mode <mode>`: Control how Playground prepares WordPress before booting. Defaults to `download-and-install`. Other options: `install-from-existing-files` (install using files you've mounted), `install-from-existing-files-if-needed` (same, but skip setup when an existing site is detected), and `do-not-attempt-installing` (never download or install WordPress).
95
95
  - `--skip-sqlite-setup`: Do not set up the SQLite database integration.
96
96
  - `--verbosity`: Output logs and progress messages (choices: "quiet", "normal", "debug"). Defaults to "normal".
97
97
 
@@ -10,7 +10,6 @@ import { type RunCLIArgs, type SpawnedWorker, type WorkerType } from '../run-cli
10
10
  * implemented in TypeScript and orchestrated by this class.
11
11
  */
12
12
  export declare class BlueprintsV1Handler {
13
- private phpVersion;
14
13
  private lastProgressMessage;
15
14
  private siteUrl;
16
15
  private processIdSpaceLength;
@@ -20,8 +19,8 @@ export declare class BlueprintsV1Handler {
20
19
  processIdSpaceLength: number;
21
20
  });
22
21
  getWorkerType(): WorkerType;
23
- bootPrimaryWorker(phpPort: NodeMessagePort, fileLockManagerPort: NodeMessagePort, nativeInternalDirPath: string): Promise<import("@php-wasm/universal").RemoteAPI<PlaygroundCliBlueprintV1Worker>>;
24
- bootSecondaryWorker({ worker, fileLockManagerPort, firstProcessId, nativeInternalDirPath, }: {
22
+ bootAndSetUpInitialPlayground(phpPort: NodeMessagePort, fileLockManagerPort: NodeMessagePort, nativeInternalDirPath: string): Promise<import("@php-wasm/universal").RemoteAPI<PlaygroundCliBlueprintV1Worker>>;
23
+ bootPlayground({ worker, fileLockManagerPort, firstProcessId, nativeInternalDirPath, }: {
25
24
  worker: SpawnedWorker;
26
25
  fileLockManagerPort: NodeMessagePort;
27
26
  firstProcessId: number;
@@ -3,6 +3,7 @@ import type { FileLockManager } from '@php-wasm/node';
3
3
  import { EmscriptenDownloadMonitor } from '@php-wasm/progress';
4
4
  import type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal';
5
5
  import { PHPWorker } from '@php-wasm/universal';
6
+ import { type WordPressInstallMode } from '@wp-playground/wordpress';
6
7
  import { type MessagePort } from 'worker_threads';
7
8
  export interface Mount {
8
9
  hostPath: string;
@@ -29,6 +30,7 @@ export type WorkerBootOptions = {
29
30
  nativeInternalDirPath: string;
30
31
  };
31
32
  export type PrimaryWorkerBootOptions = WorkerBootOptions & {
33
+ wordpressInstallMode: WordPressInstallMode;
32
34
  wpVersion?: string;
33
35
  wordPressZip?: ArrayBuffer;
34
36
  sqliteIntegrationPluginZip?: ArrayBuffer;
@@ -36,7 +38,7 @@ export type PrimaryWorkerBootOptions = WorkerBootOptions & {
36
38
  };
37
39
  interface WorkerBootRequestHandlerOptions {
38
40
  siteUrl: string;
39
- allow?: string;
41
+ followSymlinks: boolean;
40
42
  phpVersion: SupportedPHPVersion;
41
43
  firstProcessId: number;
42
44
  processIdSpaceLength: number;
@@ -44,6 +46,7 @@ interface WorkerBootRequestHandlerOptions {
44
46
  nativeInternalDirPath: string;
45
47
  mountsBeforeWpInstall: Array<Mount>;
46
48
  mountsAfterWpInstall: Array<Mount>;
49
+ withXdebug?: boolean;
47
50
  }
48
51
  export declare class PlaygroundCliBlueprintV1Worker extends PHPWorker {
49
52
  booted: boolean;
@@ -59,9 +62,9 @@ export declare class PlaygroundCliBlueprintV1Worker extends PHPWorker {
59
62
  * @see phpwasm-emscripten-library-file-locking-for-node.js
60
63
  */
61
64
  useFileLockManager(port: MessagePort): Promise<void>;
62
- bootAsPrimaryWorker({ siteUrl, mountsBeforeWpInstall, mountsAfterWpInstall, phpVersion: php, wordPressZip, sqliteIntegrationPluginZip, firstProcessId, processIdSpaceLength, dataSqlPath, followSymlinks, trace, internalCookieStore, withXdebug, nativeInternalDirPath, }: PrimaryWorkerBootOptions): Promise<void>;
63
- bootAsSecondaryWorker(args: WorkerBootOptions): Promise<void>;
64
- bootRequestHandler({ siteUrl, allow, phpVersion, firstProcessId, processIdSpaceLength, trace, nativeInternalDirPath, mountsBeforeWpInstall, mountsAfterWpInstall, }: WorkerBootRequestHandlerOptions): Promise<void>;
65
+ bootAndSetUpInitialWorker({ siteUrl, mountsBeforeWpInstall, mountsAfterWpInstall, phpVersion: php, wordpressInstallMode, wordPressZip, sqliteIntegrationPluginZip, firstProcessId, processIdSpaceLength, dataSqlPath, followSymlinks, trace, internalCookieStore, withXdebug, nativeInternalDirPath, }: PrimaryWorkerBootOptions): Promise<void>;
66
+ bootWorker(args: WorkerBootOptions): Promise<void>;
67
+ bootRequestHandler({ siteUrl, followSymlinks, phpVersion, firstProcessId, processIdSpaceLength, trace, nativeInternalDirPath, mountsBeforeWpInstall, mountsAfterWpInstall, withXdebug, }: WorkerBootRequestHandlerOptions): Promise<void>;
65
68
  dispose(): Promise<void>;
66
69
  }
67
70
  export {};
@@ -21,8 +21,8 @@ export declare class BlueprintsV2Handler {
21
21
  processIdSpaceLength: number;
22
22
  });
23
23
  getWorkerType(): WorkerType;
24
- bootPrimaryWorker(phpPort: NodeMessagePort, fileLockManagerPort: NodeMessagePort, nativeInternalDirPath: string): Promise<RemoteAPI<PlaygroundCliBlueprintV2Worker>>;
25
- bootSecondaryWorker({ worker, fileLockManagerPort, firstProcessId, nativeInternalDirPath, }: {
24
+ bootAndSetUpInitialPlayground(phpPort: NodeMessagePort, fileLockManagerPort: NodeMessagePort, nativeInternalDirPath: string): Promise<RemoteAPI<PlaygroundCliBlueprintV2Worker>>;
25
+ bootPlayground({ worker, fileLockManagerPort, firstProcessId, nativeInternalDirPath, }: {
26
26
  worker: SpawnedWorker;
27
27
  fileLockManagerPort: NodeMessagePort;
28
28
  firstProcessId: number;
@@ -56,8 +56,8 @@ export declare class PlaygroundCliBlueprintV2Worker extends PHPWorker {
56
56
  * @see phpwasm-emscripten-library-file-locking-for-node.js
57
57
  */
58
58
  useFileLockManager(port: MessagePort): Promise<void>;
59
- bootAsPrimaryWorker(args: PrimaryWorkerBootArgs): Promise<void>;
60
- bootAsSecondaryWorker(args: SecondaryWorkerBootArgs): Promise<void>;
59
+ bootAndSetUpInitialWorker(args: PrimaryWorkerBootArgs): Promise<void>;
60
+ bootWorker(args: SecondaryWorkerBootArgs): Promise<void>;
61
61
  runBlueprintV2(args: WorkerRunBlueprintArgs): Promise<void>;
62
62
  bootRequestHandler({ siteUrl, allow, phpVersion, createFiles, constants, phpIniEntries, firstProcessId, processIdSpaceLength, trace, nativeInternalDirPath, withXdebug, onPHPInstanceCreated, }: WorkerBootRequestHandlerOptions): Promise<void>;
63
63
  dispose(): Promise<void>;
package/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";const n=require("./run-cli-Dz_ghzvE.cjs");n.parseOptionsAndRunCLI();
1
+ "use strict";const n=require("./run-cli-DJ9bUpjg.cjs");n.parseOptionsAndRunCLI();
2
2
  //# sourceMappingURL=cli.cjs.map
package/cli.js CHANGED
@@ -1,3 +1,3 @@
1
- import { p } from "./run-cli-BBfr5tmj.js";
1
+ import { p } from "./run-cli-g3_uJkf5.js";
2
2
  p();
3
3
  //# sourceMappingURL=cli.js.map
package/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./run-cli-Dz_ghzvE.cjs");exports.LogVerbosity=e.LogVerbosity;exports.parseOptionsAndRunCLI=e.parseOptionsAndRunCLI;exports.runCLI=e.runCLI;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./run-cli-DJ9bUpjg.cjs");exports.LogVerbosity=e.LogVerbosity;exports.parseOptionsAndRunCLI=e.parseOptionsAndRunCLI;exports.runCLI=e.runCLI;
2
2
  //# sourceMappingURL=index.cjs.map
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { L as o, p as a, r as n } from "./run-cli-BBfr5tmj.js";
1
+ import { L as o, p as a, r as n } from "./run-cli-g3_uJkf5.js";
2
2
  export {
3
3
  o as LogVerbosity,
4
4
  a as parseOptionsAndRunCLI,
@@ -10,6 +10,7 @@ export declare class LoadBalancer {
10
10
  workerLoads: WorkerLoad[];
11
11
  constructor(initialWorker: RemoteAPI<PlaygroundCliWorker>);
12
12
  addWorker(worker: RemoteAPI<PlaygroundCliWorker>): void;
13
+ removeWorker(worker: RemoteAPI<PlaygroundCliWorker>): Promise<void>;
13
14
  handleRequest(request: PHPRequest): Promise<PHPResponse>;
14
15
  }
15
16
  export {};
@@ -1,9 +1,9 @@
1
- import { createNodeFsMountHandler as l } from "@php-wasm/node";
2
- import r, { existsSync as c } from "fs";
3
- import m, { basename as p, join as h } from "path";
4
- function $(e) {
5
- const t = [];
6
- for (const n of e) {
1
+ import { createNodeFsMountHandler as h } from "@php-wasm/node";
2
+ import r, { existsSync as l } from "fs";
3
+ import d, { basename as p, join as c } from "path";
4
+ function $(t) {
5
+ const e = [];
6
+ for (const n of t) {
7
7
  const o = n.split(":");
8
8
  if (o.length !== 2)
9
9
  throw new Error(`Invalid mount format: ${n}.
@@ -11,32 +11,32 @@ function $(e) {
11
11
  If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
12
12
  Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);
13
13
  const [s, i] = o;
14
- if (!c(s))
14
+ if (!l(s))
15
15
  throw new Error(`Host path does not exist: ${s}`);
16
- t.push({ hostPath: s, vfsPath: i });
16
+ e.push({ hostPath: s, vfsPath: i });
17
17
  }
18
- return t;
18
+ return e;
19
19
  }
20
- function x(e) {
21
- if (e.length % 2 !== 0)
20
+ function x(t) {
21
+ if (t.length % 2 !== 0)
22
22
  throw new Error("Invalid mount format. Expected: /host/path /vfs/path");
23
- const t = [];
24
- for (let n = 0; n < e.length; n += 2) {
25
- const o = e[n], s = e[n + 1];
26
- if (!c(o))
23
+ const e = [];
24
+ for (let n = 0; n < t.length; n += 2) {
25
+ const o = t[n], s = t[n + 1];
26
+ if (!l(o))
27
27
  throw new Error(`Host path does not exist: ${o}`);
28
- t.push({
29
- hostPath: m.resolve(process.cwd(), o),
28
+ e.push({
29
+ hostPath: d.resolve(process.cwd(), o),
30
30
  vfsPath: s
31
31
  });
32
32
  }
33
- return t;
33
+ return e;
34
34
  }
35
- async function N(e, t) {
36
- for (const n of t)
37
- await e.mount(
35
+ async function N(t, e) {
36
+ for (const n of e)
37
+ await t.mount(
38
38
  n.vfsPath,
39
- l(n.hostPath)
39
+ h(n.hostPath)
40
40
  );
41
41
  }
42
42
  const u = {
@@ -58,31 +58,31 @@ const u = {
58
58
  `
59
59
  }
60
60
  };
61
- function E(e) {
62
- const t = e.autoMount, n = [...e.mount || []], o = [...e["mount-before-install"] || []], s = {
63
- ...e,
61
+ function M(t) {
62
+ const e = t.autoMount, n = [...t.mount || []], o = [...t["mount-before-install"] || []], s = {
63
+ ...t,
64
64
  mount: n,
65
65
  "mount-before-install": o,
66
66
  "additional-blueprint-steps": [
67
- ...e["additional-blueprint-steps"] || []
67
+ ...t["additional-blueprint-steps"] || []
68
68
  ]
69
69
  };
70
- if (g(t)) {
71
- const i = p(t);
70
+ if (g(e)) {
71
+ const i = p(e);
72
72
  n.push({
73
- hostPath: t,
73
+ hostPath: e,
74
74
  vfsPath: `/wordpress/wp-content/plugins/${i}`
75
75
  }), s["additional-blueprint-steps"].push({
76
76
  step: "activatePlugin",
77
- pluginPath: `/wordpress/wp-content/plugins/${p(t)}`
77
+ pluginPath: `/wordpress/wp-content/plugins/${p(e)}`
78
78
  });
79
- } else if (w(t)) {
80
- const i = p(t);
79
+ } else if (w(e)) {
80
+ const i = p(e);
81
81
  n.push({
82
- hostPath: t,
82
+ hostPath: e,
83
83
  vfsPath: `/wordpress/wp-content/themes/${i}`
84
84
  }), s["additional-blueprint-steps"].push(
85
- e["experimental-blueprints-v2-runner"] ? {
85
+ t["experimental-blueprints-v2-runner"] ? {
86
86
  step: "activateTheme",
87
87
  themeDirectoryName: i
88
88
  } : {
@@ -90,42 +90,42 @@ function E(e) {
90
90
  themeFolderName: i
91
91
  }
92
92
  );
93
- } else if (f(t)) {
94
- const i = r.readdirSync(t);
93
+ } else if (f(e)) {
94
+ const i = r.readdirSync(e);
95
95
  for (const a of i)
96
96
  a !== "index.php" && n.push({
97
- hostPath: `${t}/${a}`,
97
+ hostPath: `${e}/${a}`,
98
98
  vfsPath: `/wordpress/wp-content/${a}`
99
99
  });
100
100
  s["additional-blueprint-steps"].push(u);
101
- } else d(t) ? (o.push({ hostPath: t, vfsPath: "/wordpress" }), s.mode = "apply-to-existing-site", s["additional-blueprint-steps"].push(u)) : (n.push({ hostPath: t, vfsPath: "/wordpress" }), s.mode = "mount-only");
101
+ } else m(e) ? (o.push({ hostPath: e, vfsPath: "/wordpress" }), s.mode = "apply-to-existing-site", s["additional-blueprint-steps"].push(u), s.wordpressInstallMode || (s.wordpressInstallMode = "install-from-existing-files-if-needed")) : (n.push({ hostPath: e, vfsPath: "/wordpress" }), s.mode = "mount-only");
102
102
  return s;
103
103
  }
104
- function d(e) {
105
- const t = r.readdirSync(e);
106
- return t.includes("wp-admin") && t.includes("wp-includes") && t.includes("wp-content");
104
+ function m(t) {
105
+ const e = r.readdirSync(t);
106
+ return e.includes("wp-admin") && e.includes("wp-includes") && e.includes("wp-content");
107
107
  }
108
- function f(e) {
109
- const t = r.readdirSync(e);
110
- return t.includes("themes") || t.includes("plugins") || t.includes("mu-plugins") || t.includes("uploads");
108
+ function f(t) {
109
+ const e = r.readdirSync(t);
110
+ return e.includes("themes") || e.includes("plugins") || e.includes("mu-plugins") || e.includes("uploads");
111
111
  }
112
- function w(e) {
113
- if (!r.readdirSync(e).includes("style.css"))
112
+ function w(t) {
113
+ if (!r.readdirSync(t).includes("style.css"))
114
114
  return !1;
115
- const n = r.readFileSync(h(e, "style.css"), "utf8");
115
+ const n = r.readFileSync(c(t, "style.css"), "utf8");
116
116
  return !!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(n);
117
117
  }
118
- function g(e) {
119
- const t = r.readdirSync(e), n = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
120
- return !!t.filter((s) => s.endsWith(".php")).find((s) => {
121
- const i = r.readFileSync(h(e, s), "utf8");
118
+ function g(t) {
119
+ const e = r.readdirSync(t), n = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
120
+ return !!e.filter((s) => s.endsWith(".php")).find((s) => {
121
+ const i = r.readFileSync(c(t, s), "utf8");
122
122
  return !!n.exec(i);
123
123
  });
124
124
  }
125
125
  export {
126
126
  x as a,
127
- E as e,
127
+ M as e,
128
128
  N as m,
129
129
  $ as p
130
130
  };
131
- //# sourceMappingURL=mounts-D1_eXSTw.js.map
131
+ //# sourceMappingURL=mounts-ChxECdbN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mounts-D1_eXSTw.js","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
1
+ {"version":3,"file":"mounts-ChxECdbN.js","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t\tif (!newArgs.wordpressInstallMode) {\n\t\t\tnewArgs.wordpressInstallMode =\n\t\t\t\t'install-from-existing-files-if-needed';\n\t\t}\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ "use strict";const c=require("@php-wasm/node"),r=require("fs"),a=require("path");function l(t){const e=[];for(const n of t){const o=n.split(":");if(o.length!==2)throw new Error(`Invalid mount format: ${n}.
2
+ Expected format: /host/path:/vfs/path.
3
+ If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
4
+ Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);const[s,i]=o;if(!r.existsSync(s))throw new Error(`Host path does not exist: ${s}`);e.push({hostPath:s,vfsPath:i})}return e}function h(t){if(t.length%2!==0)throw new Error("Invalid mount format. Expected: /host/path /vfs/path");const e=[];for(let n=0;n<t.length;n+=2){const o=t[n],s=t[n+1];if(!r.existsSync(o))throw new Error(`Host path does not exist: ${o}`);e.push({hostPath:a.resolve(process.cwd(),o),vfsPath:s})}return e}async function d(t,e){for(const n of e)await t.mount(n.vfsPath,c.createNodeFsMountHandler(n.hostPath))}const p={step:"runPHP",code:{filename:"activate-theme.php",content:`<?php
5
+ $docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';
6
+ require_once "$docroot/wp-load.php";
7
+ $theme = wp_get_theme();
8
+ if (!$theme->exists()) {
9
+ $themes = wp_get_themes();
10
+ if (count($themes) > 0) {
11
+ $themeName = array_keys($themes)[0];
12
+ switch_theme($themeName);
13
+ }
14
+ }
15
+ `}};function m(t){const e=t.autoMount,n=[...t.mount||[]],o=[...t["mount-before-install"]||[]],s={...t,mount:n,"mount-before-install":o,"additional-blueprint-steps":[...t["additional-blueprint-steps"]||[]]};if(P(e)){const i=a.basename(e);n.push({hostPath:e,vfsPath:`/wordpress/wp-content/plugins/${i}`}),s["additional-blueprint-steps"].push({step:"activatePlugin",pluginPath:`/wordpress/wp-content/plugins/${a.basename(e)}`})}else if(g(e)){const i=a.basename(e);n.push({hostPath:e,vfsPath:`/wordpress/wp-content/themes/${i}`}),s["additional-blueprint-steps"].push(t["experimental-blueprints-v2-runner"]?{step:"activateTheme",themeDirectoryName:i}:{step:"activateTheme",themeFolderName:i})}else if(w(e)){const i=r.readdirSync(e);for(const u of i)u!=="index.php"&&n.push({hostPath:`${e}/${u}`,vfsPath:`/wordpress/wp-content/${u}`});s["additional-blueprint-steps"].push(p)}else f(e)?(o.push({hostPath:e,vfsPath:"/wordpress"}),s.mode="apply-to-existing-site",s["additional-blueprint-steps"].push(p),s.wordpressInstallMode||(s.wordpressInstallMode="install-from-existing-files-if-needed")):(n.push({hostPath:e,vfsPath:"/wordpress"}),s.mode="mount-only");return s}function f(t){const e=r.readdirSync(t);return e.includes("wp-admin")&&e.includes("wp-includes")&&e.includes("wp-content")}function w(t){const e=r.readdirSync(t);return e.includes("themes")||e.includes("plugins")||e.includes("mu-plugins")||e.includes("uploads")}function g(t){if(!r.readdirSync(t).includes("style.css"))return!1;const n=r.readFileSync(a.join(t,"style.css"),"utf8");return!!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(n)}function P(t){const e=r.readdirSync(t),n=/^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;return!!e.filter(s=>s.endsWith(".php")).find(s=>{const i=r.readFileSync(a.join(t,s),"utf8");return!!n.exec(i)})}exports.expandAutoMounts=m;exports.mountResources=d;exports.parseMountDirArguments=h;exports.parseMountWithDelimiterArguments=l;
16
+ //# sourceMappingURL=mounts-R4uHe-O-.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mounts-BJFrPHGW.cjs","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
1
+ {"version":3,"file":"mounts-R4uHe-O-.cjs","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t\tif (!newArgs.wordpressInstallMode) {\n\t\t\tnewArgs.wordpressInstallMode =\n\t\t\t\t'install-from-existing-files-if-needed';\n\t\t}\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-playground/cli",
3
- "version": "3.0.18",
3
+ "version": "3.0.20",
4
4
  "description": "WordPress Playground CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "bin": {
35
35
  "wp-playground-cli": "wp-playground.js"
36
36
  },
37
- "gitHead": "0cc6674fcad128d2f9cdbc1163d671309d0e3211",
37
+ "gitHead": "8fb1044d507cb9fc8d53a24b60d8d37a277c2a9f",
38
38
  "dependencies": {
39
39
  "@zip.js/zip.js": "2.7.57",
40
40
  "ajv": "8.12.0",
@@ -61,16 +61,16 @@
61
61
  "ws": "8.18.3",
62
62
  "xml2js": "0.6.2",
63
63
  "yargs": "17.7.2",
64
- "@php-wasm/logger": "3.0.18",
65
- "@php-wasm/progress": "3.0.18",
66
- "@php-wasm/universal": "3.0.18",
67
- "@wp-playground/blueprints": "3.0.18",
68
- "@wp-playground/common": "3.0.18",
69
- "@wp-playground/wordpress": "3.0.18",
70
- "@php-wasm/node": "3.0.18",
71
- "@php-wasm/util": "3.0.18",
72
- "@wp-playground/storage": "3.0.18",
73
- "@php-wasm/xdebug-bridge": "3.0.18"
64
+ "@php-wasm/logger": "3.0.20",
65
+ "@php-wasm/progress": "3.0.20",
66
+ "@php-wasm/universal": "3.0.20",
67
+ "@wp-playground/blueprints": "3.0.20",
68
+ "@wp-playground/common": "3.0.20",
69
+ "@wp-playground/wordpress": "3.0.20",
70
+ "@php-wasm/node": "3.0.20",
71
+ "@php-wasm/util": "3.0.20",
72
+ "@wp-playground/storage": "3.0.20",
73
+ "@php-wasm/xdebug-bridge": "3.0.20"
74
74
  },
75
75
  "packageManager": "npm@10.9.2",
76
76
  "overrides": {