From 76a27039d185b488ccfe13b817006c6ef1e99249 Mon Sep 17 00:00:00 2001 From: Deepu Mungamuri Date: Wed, 25 Mar 2026 15:01:32 +0530 Subject: [PATCH] refactor: rename plugin and dev command from webapp/multiframework to webui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Package: @salesforce/plugin-multiframework-dev → @salesforce/plugin-webui-dev - Command topic: multi-framework → webui (sf multi-framework dev → sf webui dev) - Metadata folder: webapplications → webui - Rename src/commands/multi-framework/ → src/commands/webui/ - Rename messages/webapp.dev.md → messages/webui.dev.md with improved help text - Rename schemas/webapp-dev.json → schemas/webui-dev.json - Update webappDiscovery: WEBAPPLICATIONS_FOLDER and relative path to webui - Update all error messages, tests, and documentation Made-with: Cursor --- COMMANDS.md | 40 +-- README.md | 26 +- ...BAPP_DEV_GUIDE.md => SF_WEBUI_DEV_GUIDE.md | 120 ++++----- command-snapshot.json | 4 +- messages/webapp.dev.md | 240 ----------------- messages/webui.dev.md | 247 ++++++++++++++++++ package.json | 10 +- schemas/{webapp-dev.json => webui-dev.json} | 2 +- src/commands/{webapp => webui}/dev.ts | 26 +- src/config/types.ts | 2 +- src/config/webappDiscovery.ts | 90 +++---- src/proxy/ProxyServer.ts | 31 +-- .../{webapp => webui}/_cleanup.nut.ts | 0 test/commands/{webapp => webui}/dev.nut.ts | 54 ++-- test/commands/{webapp => webui}/dev.test.ts | 2 +- .../commands/{webapp => webui}/devPort.nut.ts | 2 +- .../{webapp => webui}/devWithUrl.nut.ts | 14 +- .../helpers/devServerUtils.ts | 6 +- .../helpers/webappProjectUtils.ts | 26 +- test/config/webappDiscovery.test.ts | 18 +- 20 files changed, 488 insertions(+), 472 deletions(-) rename SF_WEBAPP_DEV_GUIDE.md => SF_WEBUI_DEV_GUIDE.md (76%) delete mode 100644 messages/webapp.dev.md create mode 100644 messages/webui.dev.md rename schemas/{webapp-dev.json => webui-dev.json} (84%) rename src/commands/{webapp => webui}/dev.ts (96%) rename test/commands/{webapp => webui}/_cleanup.nut.ts (100%) rename test/commands/{webapp => webui}/dev.nut.ts (84%) rename test/commands/{webapp => webui}/dev.test.ts (99%) rename test/commands/{webapp => webui}/devPort.nut.ts (98%) rename test/commands/{webapp => webui}/devWithUrl.nut.ts (97%) rename test/commands/{webapp => webui}/helpers/devServerUtils.ts (97%) rename test/commands/{webapp => webui}/helpers/webappProjectUtils.ts (86%) diff --git a/COMMANDS.md b/COMMANDS.md index 2dde89a..dd67c15 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -2,43 +2,47 @@ -- [`sf webapp dev`](#sf-webapp-dev) +- [`sf webui dev`](#sf-webui-dev) -## `sf webapp dev` +## `sf webui dev` -Preview a web app locally without needing to deploy +Start a local development proxy server for webui webapp development with Salesforce authentication. ``` USAGE - $ sf webapp dev -n [--json] [--flags-dir ] [-t ] [-p ] + $ sf webui dev -n -o [--json] [--flags-dir ] [-u ] [-p ] [--open] -FLAGS - -n, --name= (required) Identifies the Web Application - -p, --port= [default: 5173] Port for the dev server - -t, --target= Selects which Web Application target to use for the preview (e.g., Lightning App, Site) +REQUIRED FLAGS + -n, --name= Name of the webapp (must match webapplication.json) + -o, --target-org= Salesforce org to authenticate against + +OPTIONAL FLAGS + -u, --url= Dev server URL. Command mode: override default 5173. URL-only: required (server must be running) + -p, --port= Proxy server port (default: 4545) + --open Open browser automatically GLOBAL FLAGS --flags-dir= Import flag values from a directory. --json Format output as json. DESCRIPTION - Preview a web app locally without needing to deploy - - Starts a local development server for a Web Application, using the local project files. This enables rapid - development with hot reloading and immediate feedback. + Starts a local HTTP proxy that injects Salesforce authentication and routes + requests between your dev server and Salesforce APIs. In command mode, + spawns and monitors the dev server (default URL: localhost:5173). In + URL-only mode, connects to an already-running dev server. EXAMPLES - Start the development server: + Command mode (CLI starts dev server, default port 5173): - $ sf webapp dev --name myWebApp + $ sf webui dev --name myapp --target-org myorg --open - Start the development server with a specific target: + URL-only mode (dev server already running): - $ sf webapp dev --name myWebApp --target "LightningApp" + $ sf webui dev --name myapp --target-org myorg --url http://localhost:5173 --open - Start the development server on a custom port: + Custom proxy port: - $ sf webapp dev --name myWebApp --port 8080 + $ sf webui dev --name myapp --target-org myorg --port 8080 --open ``` diff --git a/README.md b/README.md index 0c2d284..2113c6d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# plugin-app-dev +# plugin-webui-dev -[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-app-dev.svg?label=@salesforce/plugin-app-dev)](https://www.npmjs.com/package/@salesforce/plugin-app-dev) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-app-dev.svg)](https://npmjs.org/package/@salesforce/plugin-app-dev) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) +[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-webui-dev.svg?label=@salesforce/plugin-webui-dev)](https://www.npmjs.com/package/@salesforce/plugin-webui-dev) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-webui-dev.svg)](https://npmjs.org/package/@salesforce/plugin-webui-dev) [![License](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) # Salesforce CLI App Dev Plugin @@ -24,7 +24,7 @@ We always recommend using the latest version of these commands bundled with the 1. **Install the plugin:** ```bash - sf plugins install @salesforce/plugin-app-dev + sf plugins install @salesforce/plugin-webui-dev ``` 2. **Authenticate with Salesforce:** @@ -50,12 +50,12 @@ We always recommend using the latest version of these commands bundled with the 4. **Start development:** ```bash - sf webapp dev --name myapp --target-org myorg --open + sf webui dev --name myapp --target-org myorg --open ``` ## Documentation -📚 **[Complete Guide](SF_WEBAPP_DEV_GUIDE.md)** - Comprehensive documentation covering: +📚 **[Complete Guide](SF_WEBUI_DEV_GUIDE.md)** - Comprehensive documentation covering: - Overview and architecture - Getting started (5-minute quick start) @@ -69,7 +69,7 @@ We always recommend using the latest version of these commands bundled with the ## Install ```bash -sf plugins install @salesforce/plugin-app-dev@x.y.z +sf plugins install @salesforce/plugin-webui-dev@x.y.z ``` ## Issues @@ -101,7 +101,7 @@ To build the plugin locally, make sure to have yarn installed and run the follow ```bash # Clone the repository -git clone git@github.com:salesforcecli/plugin-app-dev +git clone git@github.com:salesforcecli/plugin-webui-dev # Install the dependencies and compile yarn && yarn build @@ -125,7 +125,7 @@ sf plugins ## Commands -### `sf webapp dev` +### `sf webui dev` Start a local development proxy server for webapp development with Salesforce authentication. @@ -136,7 +136,7 @@ Start a local development proxy server for webapp development with Salesforce au ```bash USAGE - $ sf webapp dev --name --target-org [options] + $ sf webui dev --name --target-org [options] REQUIRED FLAGS -n, --name= Name of the webapp (must match webapplication.json) @@ -156,18 +156,18 @@ DESCRIPTION EXAMPLES Command mode (CLI starts dev server, default port 5173): - $ sf webapp dev --name myapp --target-org myorg --open + $ sf webui dev --name myapp --target-org myorg --open URL-only mode (dev server already running): - $ sf webapp dev --name myapp --target-org myorg --url http://localhost:5173 --open + $ sf webui dev --name myapp --target-org myorg --url http://localhost:5173 --open Custom proxy port: - $ sf webapp dev --name myapp --target-org myorg --port 8080 --open + $ sf webui dev --name myapp --target-org myorg --port 8080 --open SEE ALSO - - Complete Guide: SF_WEBAPP_DEV_GUIDE.md + - Complete Guide: SF_WEBUI_DEV_GUIDE.md ``` diff --git a/SF_WEBAPP_DEV_GUIDE.md b/SF_WEBUI_DEV_GUIDE.md similarity index 76% rename from SF_WEBAPP_DEV_GUIDE.md rename to SF_WEBUI_DEV_GUIDE.md index 4095bce..fd9a988 100644 --- a/SF_WEBAPP_DEV_GUIDE.md +++ b/SF_WEBUI_DEV_GUIDE.md @@ -1,4 +1,4 @@ -# Salesforce Webapp Dev Command Guide +# Salesforce Multi-Framework Dev Command Guide > **Develop web applications with seamless Salesforce integration** @@ -6,11 +6,11 @@ ## Overview -The `sf webapp dev` command enables local development of modern web applications (React, Vue, Angular, etc.) with automatic Salesforce authentication. It intelligently discovers your webapp configuration, handles proxy routing, injects authentication headers, and supports hot reload - so you can focus on building your app. +The `sf webui dev` command enables local development of modern web applications (React, Vue, Angular, etc.) with automatic Salesforce authentication. It intelligently discovers your webapp configuration, handles proxy routing, injects authentication headers, and supports hot reload - so you can focus on building your app. ### Key Features -- **Auto-Discovery**: Automatically finds webapps in `webapplications/` folder +- **Auto-Discovery**: Automatically finds webapps in `webui/` folder - **Optional Manifest**: `webapplication.json` is optional - uses sensible defaults - **Auto-Selection**: Automatically selects webapp when running from inside its folder - **Interactive Selection**: Prompts with arrow-key navigation when multiple webapps exist @@ -29,7 +29,7 @@ The `sf webapp dev` command enables local development of modern web applications ``` my-sfdx-project/ ├── sfdx-project.json -└── force-app/main/default/webapplications/ +└── force-app/main/default/webui/ └── my-app/ ├── my-app.webapplication-meta.xml ├── package.json @@ -40,7 +40,7 @@ my-sfdx-project/ ### 2. Run the command ```bash -sf webapp dev --target-org myOrg --open +sf webui dev --target-org myOrg --open ``` ### 3. Start developing @@ -60,39 +60,39 @@ Browser opens to `http://localhost:4545` with your app running and Salesforce au ## Command Syntax ```bash -sf webapp dev [OPTIONS] +sf webui dev [OPTIONS] ``` ### Options -| Option | Short | Description | Default | -| -------------- | ----- | ----------------------------------------------- | ------------- | -| `--target-org` | `-o` | Salesforce org alias or username | Required | -| `--name` | `-n` | Web application name (folder name) | Auto-discover | -| `--url` | `-u` | Explicit dev server URL | Auto-detect | -| `--port` | `-p` | Proxy server port | 4545 | -| `--open` | `-b` | Open browser automatically | false | +| Option | Short | Description | Default | +| -------------- | ----- | ---------------------------------- | ------------- | +| `--target-org` | `-o` | Salesforce org alias or username | Required | +| `--name` | `-n` | Web application name (folder name) | Auto-discover | +| `--url` | `-u` | Explicit dev server URL | Auto-detect | +| `--port` | `-p` | Proxy server port | 4545 | +| `--open` | `-b` | Open browser automatically | false | ### Examples ```bash # Simplest - auto-discovers webapplication.json -sf webapp dev --target-org myOrg +sf webui dev --target-org myOrg # With browser auto-open -sf webapp dev --target-org myOrg --open +sf webui dev --target-org myOrg --open # Specify webapp by name (when multiple exist) -sf webapp dev --name myApp --target-org myOrg +sf webui dev --name myApp --target-org myOrg # Custom port -sf webapp dev --target-org myOrg --port 8080 +sf webui dev --target-org myOrg --port 8080 # Explicit dev server URL (skip auto-detection) -sf webapp dev --target-org myOrg --url http://localhost:5173 +sf webui dev --target-org myOrg --url http://localhost:5173 # Debug mode -SF_LOG_LEVEL=debug sf webapp dev --target-org myOrg +SF_LOG_LEVEL=debug sf webui dev --target-org myOrg ``` --- @@ -105,7 +105,7 @@ The command discovers webapps using a simplified, deterministic algorithm. Webap ```mermaid flowchart TD - Start["sf webapp dev"] --> CheckInside{"Inside webapplications/
webapp folder?"} + Start["sf webui dev"] --> CheckInside{"Inside webui/
webapp folder?"} CheckInside -->|Yes| HasNameInside{"--name provided?"} HasNameInside -->|Yes, different| ErrorConflict["Error: --name conflicts
with current directory"] @@ -113,7 +113,7 @@ flowchart TD CheckInside -->|No| CheckSFDX{"In SFDX project?
(sfdx-project.json)"} - CheckSFDX -->|Yes| CheckPath["Check force-app/main/
default/webapplications/"] + CheckSFDX -->|Yes| CheckPath["Check force-app/main/
default/webui/"] CheckPath --> HasName{"--name provided?"} CheckSFDX -->|No| CheckMetaXml{"Current dir has
.webapplication-meta.xml?"} @@ -148,7 +148,7 @@ flowchart TD my-sfdx-project/ ├── sfdx-project.json # SFDX project marker └── force-app/main/default/ - └── webapplications/ # Standard SFDX location + └── webui/ # Standard SFDX location ├── app-one/ # Webapp 1 (with dev config) │ ├── app-one.webapplication-meta.xml # Required: identifies as webapp │ ├── webapplication.json # Optional: dev configuration @@ -164,8 +164,8 @@ my-sfdx-project/ The command uses a simplified, deterministic approach: -1. **Inside webapp folder**: If running from `webapplications//` or deeper, auto-selects that webapp -2. **SFDX project root**: Uses fixed path `force-app/main/default/webapplications/` +1. **Inside webapp folder**: If running from `webui//` or deeper, auto-selects that webapp +2. **SFDX project root**: Uses fixed path `force-app/main/default/webui/` 3. **Standalone**: If current directory has a `.webapplication-meta.xml` file, uses it directly **Important**: Only directories containing a `{name}.webapplication-meta.xml` file are recognized as valid webapps. @@ -177,9 +177,9 @@ When multiple webapps are found, you'll see an interactive prompt: ``` Found 3 webapps in project ? Select the webapp to run: (Use arrow keys) -❯ app-one (webapplications/app-one) - app-two (webapplications/app-two) [no manifest] - app-three (webapplications/app-three) +❯ app-one (webui/app-one) + app-two (webui/app-two) [no manifest] + app-three (webui/app-three) ``` Format: @@ -238,10 +238,10 @@ Browser → Proxy → [Auth Headers Injected] → Salesforce → Response The command operates in two distinct modes based on configuration: -| Mode | Configuration | Behavior | -|------|---------------|----------| -| **Command mode** | `dev.command` is set (or default `npm run dev`) | CLI starts the dev server. URL defaults to `http://localhost:5173`. Override with `dev.url` or `--url` if your dev server uses a different port. | -| **URL-only mode** | `dev.url` or `--url` only (no `dev.command`) | CLI assumes the dev server is already running. Does **not** start the dev server. Starts proxy only and forwards to the given URL. | +| Mode | Configuration | Behavior | +| ----------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Command mode** | `dev.command` is set (or default `npm run dev`) | CLI starts the dev server. URL defaults to `http://localhost:5173`. Override with `dev.url` or `--url` if your dev server uses a different port. | +| **URL-only mode** | `dev.url` or `--url` only (no `dev.command`) | CLI assumes the dev server is already running. Does **not** start the dev server. Starts proxy only and forwards to the given URL. | **URL precedence:** `--url` flag > `dev.url` in manifest > default `http://localhost:5173` (when command is used) @@ -251,9 +251,9 @@ The `webapplication.json` file is **optional**. All fields are also optional - m #### Dev Configuration -| Field | Type | Description | Default | -| ------------- | ------ | ----------- | ------- | -| `dev.command` | string | Command to start the dev server (e.g., `npm run dev`). When set, the CLI starts the dev server and uses default URL `http://localhost:5173` unless overridden. | `npm run dev` | +| Field | Type | Description | Default | +| ------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| `dev.command` | string | Command to start the dev server (e.g., `npm run dev`). When set, the CLI starts the dev server and uses default URL `http://localhost:5173` unless overridden. | `npm run dev` | | `dev.url` | string | Dev server URL. **Command mode**: Override the default 5173 port if needed. **URL-only mode**: Required—the CLI assumes the server is already running and does not start it. | `http://localhost:5173` | **Command mode (CLI starts dev server):** @@ -306,13 +306,13 @@ The `webapplication.json` file is **optional**. All fields are also optional - m ### Example: Minimal (No Manifest) ``` -webapplications/ +webui/ └── my-dashboard/ ├── package.json # Has "scripts": { "dev": "vite" } └── src/ ``` -Run: `sf webapp dev --target-org myOrg` +Run: `sf webui dev --target-org myOrg` Console output: @@ -325,7 +325,7 @@ Warning: No webapplication.json found for webapp "my-dashboard" → Manifest watching: disabled 💡 To customize, create a webapplication.json file in your webapp directory. -✅ Using webapp: my-dashboard (webapplications/my-dashboard) +✅ Using webapp: my-dashboard (webui/my-dashboard) ✅ Ready for development! → Proxy: http://localhost:4545 (open this in your browser) @@ -390,13 +390,13 @@ Automatically detects Salesforce Code Builder environment and binds to `0.0.0.0` The `--url` flag overrides the dev server URL. Behavior depends on whether you have a command configured: -| Scenario | Command in manifest? | `--url` behavior | -|----------|----------------------|------------------| -| URL-only mode | No | Required. CLI assumes the server is already running and does not start it. Use when you run the dev server yourself. | -| Command mode | Yes | Optional override. Default is `http://localhost:5173`. Use `--url` to point to a different port. | -| URL reachable | Either | Proxy-only: skips starting dev server, starts proxy only | -| URL not reachable | Yes (command) | Starts dev server and warns if actual URL differs from `--url` | -| URL not reachable | No (URL-only) | Error: server must be running at the given URL | +| Scenario | Command in manifest? | `--url` behavior | +| ----------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------- | +| URL-only mode | No | Required. CLI assumes the server is already running and does not start it. Use when you run the dev server yourself. | +| Command mode | Yes | Optional override. Default is `http://localhost:5173`. Use `--url` to point to a different port. | +| URL reachable | Either | Proxy-only: skips starting dev server, starts proxy only | +| URL not reachable | Yes (command) | Starts dev server and warns if actual URL differs from `--url` | +| URL not reachable | No (URL-only) | Error: server must be running at the given URL | ### Connect to Existing Dev Server (Proxy-Only Mode) @@ -409,7 +409,7 @@ npm run dev # Output: Local: http://localhost:5173/ # Terminal 2: Connect proxy to your running server -sf webapp dev --url http://localhost:5173 --target-org myOrg +sf webui dev --url http://localhost:5173 --target-org myOrg ``` **Output:** @@ -425,7 +425,7 @@ sf webapp dev --url http://localhost:5173 --target-org myOrg When using `dev.command`, the default URL is `http://localhost:5173`. Override with `--url` if your dev server uses a different port: ```bash -sf webapp dev --url http://localhost:3000 --target-org myOrg +sf webui dev --url http://localhost:3000 --target-org myOrg ``` If the URL is not reachable, the CLI starts the dev server and uses the actual URL (with a warning if it differs). @@ -439,7 +439,7 @@ If the URL is not reachable, the CLI starts the dev server and uses the actual U Ensure your webapp has the required `.webapplication-meta.xml` file: ``` -force-app/main/default/webapplications/ +force-app/main/default/webui/ └── my-app/ ├── my-app.webapplication-meta.xml # Required! ├── package.json @@ -454,8 +454,8 @@ This error occurs when you're inside one webapp folder but try to run a differen ```bash # You're in FirstWebApp folder but trying to run SecondWebApp -cd webapplications/FirstWebApp -sf webapp dev --name SecondWebApp --target-org myOrg # Error! +cd webui/FirstWebApp +sf webui dev --name SecondWebApp --target-org myOrg # Error! ``` **Solutions:** @@ -470,7 +470,7 @@ The `--name` flag matches the folder name of the webapp. ```bash # This looks for webapp named "myApp" -sf webapp dev --name myApp --target-org myOrg +sf webui dev --name myApp --target-org myOrg ``` ### "Dependencies Not Installed" / "command not found" @@ -478,7 +478,7 @@ sf webapp dev --name myApp --target-org myOrg Install dependencies in your webapp folder: ```bash -cd webapplications/my-app +cd webui/my-app npm install ``` @@ -486,13 +486,13 @@ npm install 1. Ensure dev server is running: `npm run dev` 2. Verify URL in `webapplication.json` is correct -3. Try explicit URL: `sf webapp dev --url http://localhost:5173 --target-org myOrg` +3. Try explicit URL: `sf webui dev --url http://localhost:5173 --target-org myOrg` ### "Port 4545 already in use" ```bash # Use a different port -sf webapp dev --port 8080 --target-org myOrg +sf webui dev --port 8080 --target-org myOrg # Or find and kill the process using the port lsof -i :4545 @@ -524,14 +524,14 @@ tail -f ~/.sf/sf-$(date +%Y-%m-%d).log | grep --line-buffered WebappDev | jq -r **Step 2: Run command in Terminal 2** ```bash -SF_LOG_LEVEL=debug sf webapp dev --target-org myOrg +SF_LOG_LEVEL=debug sf webui dev --target-org myOrg ``` **Example debug output:** ``` Discovering webapplication.json manifest(s)... -Using webapp: myApp at webapplications/my-app +Using webapp: myApp at webui/my-app Manifest loaded: myApp Starting dev server with command: npm run dev Dev server ready at: http://localhost:5173/ @@ -548,7 +548,7 @@ The command integrates with the Salesforce VSCode UI Preview extension (`salesfo 1. Extension detects `webapplication.json` in workspace 2. User clicks "Preview" button on the file -3. Extension executes: `sf webapp dev --target-org --open` +3. Extension executes: `sf webui dev --target-org --open` 4. If multiple webapps exist, uses `--name` to specify which one 5. Browser opens with the app running @@ -559,7 +559,7 @@ The command integrates with the Salesforce VSCode UI Preview extension (`salesfo For scripting and CI/CD, use the `--json` flag: ```bash -sf webapp dev --target-org myOrg --json +sf webui dev --target-org myOrg --json ``` Output: @@ -581,7 +581,7 @@ Output: ### Building the Plugin ```bash -cd /path/to/plugin-app-dev +cd /path/to/plugin-webui-dev # Install dependencies yarn install @@ -605,7 +605,7 @@ yarn build # Rebuild - no re-linking needed ### Project Structure ``` -plugin-app-dev/ +plugin-webui-dev/ ├── src/ │ ├── commands/webapp/ │ │ └── dev.ts # Main command implementation @@ -649,4 +649,4 @@ plugin-app-dev/ --- -**Repository:** [github.com/salesforcecli/plugin-app-dev](https://github.com/salesforcecli/plugin-app-dev) +**Repository:** [github.com/salesforcecli/plugin-webui-dev](https://github.com/salesforcecli/plugin-webui-dev) diff --git a/command-snapshot.json b/command-snapshot.json index 44c13e3..56824ac 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -1,10 +1,10 @@ [ { "alias": [], - "command": "webapp:dev", + "command": "webui:dev", "flagAliases": [], "flagChars": ["b", "n", "o", "p", "u"], "flags": ["flags-dir", "json", "name", "open", "port", "target-org", "url"], - "plugin": "@salesforce/plugin-app-dev" + "plugin": "@salesforce/plugin-webui-dev" } ] diff --git a/messages/webapp.dev.md b/messages/webapp.dev.md deleted file mode 100644 index 5d8f6a0..0000000 --- a/messages/webapp.dev.md +++ /dev/null @@ -1,240 +0,0 @@ -# summary - -Preview a web app locally without needing to deploy - -# description - -Starts a local development server for a Web Application, using the local project files. This enables rapid development with hot reloading and immediate feedback. - -The command launches a local proxy server that sits between your web application and Salesforce, automatically injecting authentication headers from the CLI's stored tokens. This allows your web app to make authenticated API calls to Salesforce without exposing credentials. - -# flags.name.summary - -Identifies the Web Application (optional) - -# flags.name.description - -The unique name of the web application as defined in webapplication.json. If not provided, the command will automatically discover webapplication.json files in the current directory and subdirectories. If only one webapplication.json is found, it will be used automatically. If multiple are found, you will be prompted to select one. - -# flags.url.summary - -Dev server origin to forward UI/HMR/static requests - -# flags.url.description - -The URL where your dev server is running (e.g., http://localhost:5173). Required if webapplication.json does not contain a dev.command or dev.url configuration. All non-Salesforce API requests will be forwarded to this URL. - -Dev server URL precedence: --url flag > manifest dev.url > URL from dev server process (started via manifest dev.command or default npm run dev). - -# flags.port.summary - -Local proxy port - -# flags.port.description - -The port on which the proxy server will listen. Your browser should connect to this port, not directly to the dev server. The proxy will forward authenticated requests to Salesforce and other requests to your dev server. - -# flags.open.summary - -Auto-open proxy URL in default browser - -# flags.open.description - -Automatically opens the proxy server URL in your default web browser when the server is ready. This saves you from manually copying and pasting the URL. The browser will open to the proxy URL (not the dev server URL directly), ensuring all requests are properly authenticated. - -# examples - -- Start the development server (auto-discovers webapplication.json): - - <%= config.bin %> <%= command.id %> --target-org myorg - -- Start the development server with explicit webapp name: - - <%= config.bin %> <%= command.id %> --name myWebApp --target-org myorg - -- Start the development server with explicit dev server URL: - - <%= config.bin %> <%= command.id %> --name myWebApp --url http://localhost:5173 --target-org myorg - -- Start with custom port and auto-open browser: - - <%= config.bin %> <%= command.id %> --target-org myorg --port 4546 --open - -- Start with debug logging (using SF_LOG_LEVEL environment variable): - - SF_LOG_LEVEL=debug <%= config.bin %> <%= command.id %> --target-org myorg - -# info.manifest-changed - -Manifest %s detected - -# info.manifest-reloaded - -✓ Manifest reloaded successfully - -# info.dev-url-changed - -Dev server URL updated to: %s - -# info.dev-server-url - -Dev server URL: %s - -# info.proxy-url - -Proxy URL: %s (open this URL in your browser) - -# info.ready-for-development - -✅ Ready for development! - → %s (open this URL in your browser) - -# info.ready-for-development-vite - -✅ Ready for development! - → %s (Vite proxy active - open this URL in your browser) - -# info.press-ctrl-c - -Press Ctrl+C to stop. - -# info.press-ctrl-c-target - -Press Ctrl+C to stop the %s. - -# info.stopped-target - -✅ Stopped %s. - -# info.stop-target-dev - -dev server - -# info.stop-target-proxy - -proxy server - -# info.stop-target-both - -dev and proxy servers - -# info.server-running - -Dev server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. - -# info.server-running-target-dev - -Dev server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. - -# info.server-running-target-proxy - -Proxy server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. - -# info.server-running-target-both - -Dev and proxy servers are running. Stop them by running "SFDX: Close Live Preview" from the VS Code command palette. - -# info.dev-server-healthy - -✓ Dev server is responding at: %s - -# info.dev-server-detected - -✅ Dev server detected at %s - -# info.start-dev-server-hint - -Start your dev server to continue development - -# warning.dev-server-not-responding - -⚠ Dev server returned status %s from: %s - -# warning.dev-server-unreachable - -⚠ Dev server is not responding at: %s - -# warning.dev-server-unreachable-status - -⚠️ Dev server unreachable at %s - -# warning.dev-server-start-hint - -The proxy server is running, but the dev server may not be started yet. -Make sure to start your dev server (e.g., 'npm run dev') before opening the browser. - -# warning.dev-command-changed - -dev.command changed to "%s" - restart the command to apply this change. - -# error.manifest-watch-failed - -Failed to watch manifest: %s - -# error.dev-url-unreachable - -Dev server unreachable at %s. -Start your dev server manually at that URL, or add dev.command to webapplication.json to start it automatically. - -# error.dev-url-unreachable-with-flag - -Dev server unreachable at %s. -Remove --url to use dev.command to start the server automatically, or ensure your dev server is running at that URL. - -# error.port-in-use - -Port %s is already in use. Try specifying a different port with the --port flag or stopping the service that's using the port. - -# error.dev-server-failed - -%s - -# info.multiple-webapps-found - -Found %s webapps in project - -# info.webapp-auto-selected - -Auto-selected webapp "%s" (running from inside its folder) - -# info.using-webapp - -✅ Using webapp: %s (%s) - -# info.starting-webapp - -✅ Starting %s - -# prompt.select-webapp - -Select the webapp to run: - -# info.no-manifest-defaults - -No webapplication.json found. Using defaults: dev command=%s, proxy port=%s - -Tip: See "sf webapp dev --help" for configuration options. - -# warning.empty-manifest - -No dev configuration in webapplication.json - using defaults (command: %s) - -Tip: See "sf webapp dev --help" for configuration options. - -# info.using-defaults - -Using default dev command: %s - -# info.url-already-available - -✅ URL %s is already available, skipping dev server startup (proxy-only mode) - -# warning.url-mismatch - -⚠️ The --url flag (%s) does not match the actual dev server URL (%s). -The proxy will use the actual dev server URL. - -# info.vite-proxy-detected - -Vite WebApp proxy detected at %s - using Vite's built-in proxy (standalone proxy skipped) - diff --git a/messages/webui.dev.md b/messages/webui.dev.md new file mode 100644 index 0000000..114a38c --- /dev/null +++ b/messages/webui.dev.md @@ -0,0 +1,247 @@ +# summary + +Preview a web application locally and in real-time, without deploying it to your org. + +# description + +This command starts a local development (dev) server so you can preview a web application using the local metadata files in your DX project. Using a local preview helps you quickly develop web applications, because you don't have to continually deploy metadata to your org. + +The command also launches a local proxy server that sits between your web application and Salesforce, automatically injecting authentication headers from Salesforce CLI's stored tokens. The proxy allows your web app to make authenticated API calls to Salesforce without exposing credentials. + +Even though you're previewing the web application locally and not deploying anything to an org, you're still required to authorize and specify an org to use this command. + +Salesforce web applications are represented by the WebApplication metadata type. + +# flags.name.summary + +Name of the web application to preview. + +# flags.name.description + +The unique name of the web application, as defined by the "name" property in the webapplication.json runtime configuration file. The webapplication.json file is located in the "webui" metadata directory of your DX project, such as force-app/main/default/webui/MyApp/webapplication.json. + +If you don't specify this flag, the command automatically discovers the webapplication.json files in the current directory and subdirectories. If the command finds only one webapplication.json, it automatically uses it. If it finds multiple files, the command prompts you to select one. + +# flags.url.summary + +URL where your developer server runs, such as https://localhost:5173. All UI, static, and hot deployment requests are forwarded to this URL. + +# flags.url.description + +You must specify this flag if the web application's webapplication.json file doesn't contain a value for either the "dev.command" or "dev.url" configuration properties. All non-Salesforce API requests are forwarded to this URL. + +If you specify this flag, it overrides the value in the webapplication.json file. + +This is the order of precedence that the dev server uses for the URL: --url flag > manifest dev.url > URL from the dev server process (which was started using either manifest dev.command or default npm run dev). + +# flags.port.summary + +Local port where the proxy server listens. + +# flags.port.description + +Be sure your browser connects to this port, and not directly to the dev server. The proxy then forwards authenticated requests to Salesforce and other requests to your local dev server. + +# flags.open.summary + +Automatically open the proxy server URL in your default browser when the dev server is ready. + +# flags.open.description + +This flag saves you from manually copying and pasting the URL. The browser opens to the proxy URL, and not the dev server URL directly, which ensures that all requests are property authenticated. + +# examples + +- Start the local development (dev) server by automatically discovering the web application's webapplication.json file; use the org with alias "myorg": + + <%= config.bin %> <%= command.id %> --target-org myorg + +- Start the dev server by explicitly specifying the web application's name: + + <%= config.bin %> <%= command.id %> --name myWebApp --target-org myorg + +- Start at the specified dev server URL: + + <%= config.bin %> <%= command.id %> --name myWebApp --url http://localhost:5173 --target-org myorg + +- Start with a custom proxy port and automatically open the proxy server URL in your browser: + + <%= config.bin %> <%= command.id %> --target-org myorg --port 4546 --open + +- Start with debug logging enabled by specifing the SF_LOG_LEVEL environment variable before running the command: + + SF_LOG_LEVEL=debug <%= config.bin %> <%= command.id %> --target-org myorg + +# info.manifest-changed + +Manifest %s detected. + +# info.manifest-reloaded + +✓ Manifest reloaded successfully. + +# info.dev-url-changed + +Dev server URL updated to: %s. + +# info.dev-server-url + +Dev server URL: %s. + +# info.proxy-url + +Proxy URL: %s (open this URL in your browser). + +# info.ready-for-development + +✅ Ready for development! + → %s (open this URL in your browser). + +# info.ready-for-development-vite + +✅ Ready for development! + → %s (Vite proxy active - open this URL in your browser). + +# info.press-ctrl-c + +Press Ctrl+C to stop. + +# info.press-ctrl-c-target + +Press Ctrl+C to stop the %s. + +# info.stopped-target + +✅ Stopped %s. + +# info.stop-target-dev + +dev server + +# info.stop-target-proxy + +proxy server + +# info.stop-target-both + +dev and proxy servers + +# info.server-running + +Dev server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. + +# info.server-running-target-dev + +Dev server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. + +# info.server-running-target-proxy + +Proxy server is running. Stop it by running "SFDX: Close Live Preview" from the VS Code command palette. + +# info.server-running-target-both + +Dev and proxy servers are running. Stop them by running "SFDX: Close Live Preview" from the VS Code command palette. + +# info.dev-server-healthy + +✓ Dev server is responding at: %s. + +# info.dev-server-detected + +✅ Dev server detected at %s. + +# info.start-dev-server-hint + +Start your dev server to continue development. + +# warning.dev-server-not-responding + +⚠ Dev server returned status %s from: %s. + +# warning.dev-server-unreachable + +⚠ Dev server is not responding at: %s. + +# warning.dev-server-unreachable-status + +⚠️ Dev server unreachable at %s. + +# warning.dev-server-start-hint + +The proxy server is running, but the dev server may not be started yet. +Make sure to start your dev server (e.g., 'npm run dev') before opening the browser. + +# warning.dev-command-changed + +dev.command changed to "%s" - restart the command to apply this change. + +# error.manifest-watch-failed + +Failed to watch manifest: %s. + +# error.dev-url-unreachable + +Dev server unreachable at %s. +Start your dev server manually at that URL, or add dev.command to webapplication.json to start it automatically. + +# error.dev-url-unreachable-with-flag + +Dev server unreachable at %s. +Remove --url to use dev.command to start the server automatically, or ensure your dev server is running at that URL. + +# error.port-in-use + +Port %s is already in use. Try specifying a different port with the --port flag or stopping the service that's using the port. + +# error.dev-server-failed + +%s + +# info.multiple-webapps-found + +Found %s webapps in project. + +# info.webapp-auto-selected + +Auto-selected webapp "%s" (running from inside its folder). + +# info.using-webapp + +✅ Using webapp: %s (%s). + +# info.starting-webapp + +✅ Starting %s. + +# prompt.select-webapp + +Select the webapp to run: + +# info.no-manifest-defaults + +No webapplication.json found. Using defaults: dev command=%s, proxy port=%s. + +Tip: See "sf webui dev --help" for configuration options. + +# warning.empty-manifest + +No dev configuration in webapplication.json - using defaults (command: %s). + +Tip: See "sf webui dev --help" for configuration options. + +# info.using-defaults + +Using default dev command: %s. + +# info.url-already-available + +✅ URL %s is already available, skipping dev server startup (proxy-only mode). + +# warning.url-mismatch + +⚠️ The --url flag (%s) does not match the actual dev server URL (%s). +The proxy will use the actual dev server URL. + +# info.vite-proxy-detected + +Vite WebApp proxy detected at %s - using Vite's built-in proxy (standalone proxy skipped). diff --git a/package.json b/package.json index 3b6217d..e332c68 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@salesforce/plugin-app-dev", + "name": "@salesforce/plugin-webui-dev", "description": "A CLI plugin for building UI that integrates with Salesforce", "version": "1.2.0", "author": "Salesforce", @@ -41,7 +41,7 @@ "/oclif.manifest.json", "/schemas" ], - "homepage": "https://github.com/salesforcecli/plugin-app-dev", + "homepage": "https://github.com/salesforcecli/plugin-webui-dev", "keywords": [ "force", "salesforce", @@ -62,13 +62,13 @@ "@salesforce/plugin-command-reference" ], "topics": { - "webapp": { - "description": "Work with Salesforce Web Apps" + "webui": { + "description": "Work with web UI apps" } }, "flexibleTaxonomy": true }, - "repository": "salesforcecli/plugin-app-dev", + "repository": "salesforcecli/plugin-webui-dev", "scripts": { "build": "wireit", "clean": "sf-clean", diff --git a/schemas/webapp-dev.json b/schemas/webui-dev.json similarity index 84% rename from schemas/webapp-dev.json rename to schemas/webui-dev.json index b3ee114..d6f76b9 100644 --- a/schemas/webapp-dev.json +++ b/schemas/webui-dev.json @@ -16,7 +16,7 @@ }, "required": ["url", "devServerUrl"], "additionalProperties": false, - "description": "Command execution result What the sf webapp dev command returns to the user" + "description": "Command execution result What the sf webui dev command returns to the user" } } } diff --git a/src/commands/webapp/dev.ts b/src/commands/webui/dev.ts similarity index 96% rename from src/commands/webapp/dev.ts rename to src/commands/webui/dev.ts index 2cc476b..90bd2c6 100644 --- a/src/commands/webapp/dev.ts +++ b/src/commands/webui/dev.ts @@ -26,9 +26,9 @@ import { ProxyServer } from '../../proxy/ProxyServer.js'; import { discoverWebapp, DEFAULT_DEV_COMMAND, type DiscoveredWebapp } from '../../config/webappDiscovery.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); -const messages = Messages.loadMessages('@salesforce/plugin-app-dev', 'webapp.dev'); +const messages = Messages.loadMessages('@salesforce/plugin-webui-dev', 'webui.dev'); -export default class WebappDev extends SfCommand { +export default class WebUIDev extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); @@ -77,7 +77,7 @@ export default class WebappDev extends SfCommand { * Prompt user to select a webapp from multiple discovered webapps * Uses interactive arrow-key selection (standard SF CLI pattern) */ - private static async promptWebappSelection(webapps: DiscoveredWebapp[]): Promise { + private static async promptWebUiSelection(webapps: DiscoveredWebapp[]): Promise { const WARNING = '\u26A0\uFE0F'; // ⚠️ const choices = webapps.map((webapp) => { @@ -133,14 +133,14 @@ export default class WebappDev extends SfCommand { intervalMs = 500, start = Date.now() ): Promise { - if (await WebappDev.isUrlReachable(url)) { + if (await WebUIDev.isUrlReachable(url)) { return true; } if (Date.now() - start >= timeoutMs) { return false; } await new Promise((r) => setTimeout(r, intervalMs)); - return WebappDev.pollUntilReachable(url, timeoutMs, intervalMs, start); + return WebUIDev.pollUntilReachable(url, timeoutMs, intervalMs, start); } /** @@ -169,11 +169,11 @@ export default class WebappDev extends SfCommand { // eslint-disable-next-line complexity public async run(): Promise { - const { flags } = await this.parse(WebappDev); + const { flags } = await this.parse(WebUIDev); // Initialize logger from @salesforce/core for debug logging // Logger respects SF_LOG_LEVEL environment variable - this.logger = await Logger.child('WebappDev'); + this.logger = await Logger.child('WebUIDev'); // Declare variables outside try block for catch block access let manifest: WebAppManifest | null = null; @@ -191,7 +191,7 @@ export default class WebappDev extends SfCommand { if (!discoveredWebapp) { this.log(messages.getMessage('info.multiple-webapps-found', [String(allWebapps.length)])); - selectedWebapp = await WebappDev.promptWebappSelection(allWebapps); + selectedWebapp = await WebUIDev.promptWebUiSelection(allWebapps); } else { selectedWebapp = discoveredWebapp; @@ -283,7 +283,7 @@ export default class WebappDev extends SfCommand { } // Check if URL is already reachable - const isReachable = await WebappDev.isUrlReachable(resolvedUrl); + const isReachable = await WebUIDev.isUrlReachable(resolvedUrl); if (isReachable) { devServerUrl = resolvedUrl; this.log(messages.getMessage('info.url-already-available', [resolvedUrl])); @@ -344,7 +344,7 @@ export default class WebappDev extends SfCommand { this.devServerManager.start(); // Poll until URL is reachable, or fail immediately on process error - const pollPromise = WebappDev.pollUntilReachable(resolvedUrl, 60_000); + const pollPromise = WebUIDev.pollUntilReachable(resolvedUrl, 60_000); const errorPromise = new Promise((_, reject) => { this.devServerManager!.once('error', (error: SfError | DevServerError) => { const devError = @@ -410,7 +410,7 @@ export default class WebappDev extends SfCommand { // Step 5: Check for Vite proxy and conditionally start standalone proxy this.logger.debug('Checking if Vite WebApp proxy is active...'); - const viteProxyActive = await WebappDev.checkViteProxyActive(devServerUrl); + const viteProxyActive = await WebUIDev.checkViteProxyActive(devServerUrl); // Track the final URL to open in browser (either proxy or dev server) let finalUrl: string; @@ -489,7 +489,7 @@ export default class WebappDev extends SfCommand { // Step 7: Open browser if requested if (flags.open) { this.logger.debug('Opening browser...'); - await WebappDev.openBrowser(finalUrl); + await WebUIDev.openBrowser(finalUrl); } // Display usage instructions @@ -577,7 +577,7 @@ export default class WebappDev extends SfCommand { // Wrap unknown errors const errorMessage = error instanceof Error ? error.message : String(error); - throw new SfError(`❌ Failed to start webapp dev command: ${errorMessage}`, 'UnexpectedError', [ + throw new SfError(`❌ Failed to start webui dev command: ${errorMessage}`, 'UnexpectedError', [ 'This is an unexpected error', 'Please try again', 'If the problem persists, check the command logs with SF_LOG_LEVEL=debug', diff --git a/src/config/types.ts b/src/config/types.ts index 77ac97b..b70f25c 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -22,7 +22,7 @@ export type { ManifestChangeEvent } from './ManifestWatcher.js'; /** * Command execution result - * What the sf webapp dev command returns to the user + * What the sf webui dev command returns to the user */ export type WebAppDevResult = { /** Proxy server URL (where user should open browser) */ diff --git a/src/config/webappDiscovery.ts b/src/config/webappDiscovery.ts index 88d3ef9..62c21a2 100644 --- a/src/config/webappDiscovery.ts +++ b/src/config/webappDiscovery.ts @@ -27,10 +27,10 @@ const logger = Logger.childFromRoot('WebappDiscovery'); export const DEFAULT_DEV_COMMAND = 'npm run dev'; /** - * Standard metadata path segment for webapplications (relative to package directory). - * Consistent with other metadata types: packagePath/main/default/webapplications + * Standard metadata path segment for webui (relative to package directory). + * Consistent with other metadata types: packagePath/main/default/webui */ -const WEBAPPLICATIONS_RELATIVE_PATH = 'main/default/webapplications'; +const WEBAPPLICATIONS_RELATIVE_PATH = 'main/default/webui'; /** * Pattern to match webapplication metadata XML files @@ -58,7 +58,7 @@ export type DiscoveredWebapp = { }; /** - * Directories to exclude when processing webapplications folder. + * Directories to exclude when processing webui folder. * Note: Directories starting with '.' are excluded separately in shouldExcludeDirectory() */ const EXCLUDED_DIRECTORIES = new Set(['node_modules', 'dist', 'build', 'out', 'coverage', '__pycache__', 'venv']); @@ -70,11 +70,11 @@ function shouldExcludeDirectory(dirName: string): boolean { return EXCLUDED_DIRECTORIES.has(dirName) || dirName.startsWith('.'); } -/** Folder name for webapplications metadata */ -const WEBAPPLICATIONS_FOLDER = 'webapplications'; +/** Folder name for webui metadata */ +const WEBAPPLICATIONS_FOLDER = 'webui'; /** - * Check if a folder name is the standard webapplications folder + * Check if a folder name is the standard webui folder */ function isWebapplicationsFolder(folderName: string): boolean { return folderName === WEBAPPLICATIONS_FOLDER; @@ -174,11 +174,11 @@ async function tryResolveSfdxProjectRoot(cwd: string): Promise { } /** - * Get all webapplications folder paths from the project's package directories. - * Consistent with other metadata types: each package can have main/default/webapplications. + * Get all webui folder paths from the project's package directories. + * Consistent with other metadata types: each package can have main/default/webui. * * @param projectRoot - Absolute path to project root (where sfdx-project.json lives) - * @returns Array of absolute paths to webapplications folders that exist + * @returns Array of absolute paths to webui folders that exist */ async function getWebapplicationsPathsFromProject(projectRoot: string): Promise { try { @@ -199,24 +199,24 @@ async function getWebapplicationsPathsFromProject(projectRoot: string): Promise< } /** - * Check if we're inside a webapplications folder by traversing upward through parent directories. + * Check if we're inside a webui folder by traversing upward through parent directories. * * This handles cases where the user runs the command from inside a webapp folder: * - * Example 1: Running from /project/force-app/main/default/webapplications/my-app/src/ - * Traverses: src -> my-app -> webapplications (found!) - * Returns: { webappsFolder: "/project/.../webapplications", currentWebappName: "my-app" } + * Example 1: Running from /project/force-app/main/default/webui/my-app/src/ + * Traverses: src -> my-app -> webui (found!) + * Returns: { webappsFolder: "/project/.../webui", currentWebappName: "my-app" } * - * Example 2: Running from /project/force-app/main/default/webapplications/my-app/ - * Checks parent: webapplications (found!) - * Returns: { webappsFolder: "/project/.../webapplications", currentWebappName: "my-app" } + * Example 2: Running from /project/force-app/main/default/webui/my-app/ + * Checks parent: webui (found!) + * Returns: { webappsFolder: "/project/.../webui", currentWebappName: "my-app" } * - * Example 3: Running from /project/force-app/main/default/webapplications/ - * Current dir is webapplications (found!) - * Returns: { webappsFolder: "/project/.../webapplications", currentWebappName: null } + * Example 3: Running from /project/force-app/main/default/webui/ + * Current dir is webui (found!) + * Returns: { webappsFolder: "/project/.../webui", currentWebappName: null } * * @param dir - Directory to start from - * @returns Object with webapplications folder path and current webapp name, or null if not found + * @returns Object with webui folder path and current webapp name, or null if not found */ function findWebapplicationsFolderUpward( dir: string @@ -226,13 +226,13 @@ function findWebapplicationsFolderUpward( const maxUpwardDepth = 10; let depth = 0; - // Walk up the directory tree looking for "webapplications" folder + // Walk up the directory tree looking for "webui" folder while (depth < maxUpwardDepth) { const dirName = basename(currentDir); const parentDir = dirname(currentDir); - // Case: Current directory IS the webapplications folder - // e.g., cwd = /project/webapplications + // Case: Current directory IS the webui folder + // e.g., cwd = /project/webui if (isWebapplicationsFolder(dirName)) { return { webappsFolder: currentDir, @@ -240,8 +240,8 @@ function findWebapplicationsFolderUpward( }; } - // Case: Parent directory is the webapplications folder - // e.g., cwd = /project/webapplications/my-app (parent is webapplications) + // Case: Parent directory is the webui folder + // e.g., cwd = /project/webui/my-app (parent is webui) if (isWebapplicationsFolder(basename(parentDir))) { return { webappsFolder: parentDir, @@ -260,16 +260,16 @@ function findWebapplicationsFolderUpward( depth++; } - // Not inside a webapplications folder + // Not inside a webui folder return null; } /** - * Discover all webapps inside the webapplications folder. + * Discover all webapps inside the webui folder. * Only directories containing a {name}.webapplication-meta.xml file are considered valid webapps. * If a webapplication.json exists, use it for dev configuration. * - * @param webappsFolderPath - Absolute path to the webapplications folder + * @param webappsFolderPath - Absolute path to the webui folder * @param cwd - Original working directory for relative path calculation * @returns Array of discovered webapps (only those with .webapplication-meta.xml) */ @@ -326,7 +326,7 @@ type FindAllWebappsResult = { webapps: DiscoveredWebapp[]; /** Name of webapp user is currently inside (folder name), null if not inside any */ currentWebappName: string | null; - /** Whether the webapplications folder was found (even if empty or no valid webapps) */ + /** Whether the webui folder was found (even if empty or no valid webapps) */ webappsFolderFound: boolean; /** Whether we're in an SFDX project context */ inSfdxProject: boolean; @@ -336,8 +336,8 @@ type FindAllWebappsResult = { * Find all webapps using simplified discovery algorithm. * * Discovery strategy (in order): - * 1. Check if inside a webapplications/ directory (upward search) - * 2. Check for SFDX project and search webapplications in all package directories + * 1. Check if inside a webui/ directory (upward search) + * 2. Check for SFDX project and search webui in all package directories * 3. If neither, check if current directory is a webapp (has .webapplication-meta.xml) * * @param cwd - Directory to search from (defaults to process.cwd()) @@ -348,15 +348,15 @@ async function findAllWebapps(cwd: string = process.cwd()): Promise or webapplications//src/ + // Step 1: Check if we're inside a webui folder (upward search) + // This handles: running from webui/ or webui//src/ const upwardResult = findWebapplicationsFolderUpward(cwd); if (upwardResult) { webappsFolder = upwardResult.webappsFolder; currentWebappName = upwardResult.currentWebappName; } else { - // Step 2: Check for SFDX project and search webapplications in all package directories + // Step 2: Check for SFDX project and search webui in all package directories const projectRoot = await tryResolveSfdxProjectRoot(cwd); if (projectRoot) { @@ -378,7 +378,7 @@ async function findAllWebapps(cwd: string = process.cwd()): Promise directory: + * 2. Inside webui/ directory: * - Auto-select current webapp * - Error if --name conflicts with current directory * @@ -470,21 +470,21 @@ export async function discoverWebapp( if (webappsFolderFound) { // Folder exists but no valid webapps (no .webapplication-meta.xml files) throw new SfError( - 'Found "webapplications" folder but no valid webapps inside it.\n' + + 'Found "webui" folder but no valid webapps inside it.\n' + 'Each webapp must have a {name}.webapplication-meta.xml file.\n\n' + 'Expected structure:\n' + - ' webapplications/\n' + + ' webui/\n' + ' └── my-app/\n' + ' ├── my-app.webapplication-meta.xml (required)\n' + ' └── webapplication.json (optional, for dev config)', 'WebappNotFoundError' ); } else if (inSfdxProject) { - // In SFDX project but webapplications folder doesn't exist + // In SFDX project but webui folder doesn't exist throw new SfError( - 'No webapplications folder found in the SFDX project.\n\n' + + 'No webui folder found in the SFDX project.\n\n' + 'Create the folder structure in any package directory (e.g. force-app, packages/my-pkg):\n' + - ' /main/default/webapplications/\n' + + ' /main/default/webui/\n' + ' └── my-app/\n' + ' ├── my-app.webapplication-meta.xml (required)\n' + ' └── webapplication.json (optional, for dev config)', @@ -495,8 +495,8 @@ export async function discoverWebapp( throw new SfError( 'No webapp found.\n\n' + 'To use this command, either:\n' + - '1. Run from an SFDX project with webapps in /main/default/webapplications/\n' + - '2. Run from inside a webapplications// directory\n' + + '1. Run from an SFDX project with webapps in /main/default/webui/\n' + + '2. Run from inside a webui// directory\n' + '3. Run from a directory containing a {name}.webapplication-meta.xml file', 'WebappNotFoundError' ); diff --git a/src/proxy/ProxyServer.ts b/src/proxy/ProxyServer.ts index 3afd3d3..3a9adfe 100644 --- a/src/proxy/ProxyServer.ts +++ b/src/proxy/ProxyServer.ts @@ -120,24 +120,21 @@ export class ProxyServer extends EventEmitter { const chunks: Buffer[] = []; const routeScript = - ''; + ""; const wrapped = Object.create(res, { writeHead: { - value: ( - code: number, - h?: Record - ) => { + value: (code: number, h?: Record) => { statusCode = code; if (h) { const merged: Record = { ...headers, - ...h + ...h, }; headers = merged; } return true; - } + }, }, write: { value: ( @@ -154,19 +151,13 @@ export class ProxyServer extends EventEmitter { actualEncoding = encoding; actualCb = cb; } - chunks.push( - Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, actualEncoding as BufferEncoding) - ); + chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, actualEncoding as BufferEncoding)); if (actualCb) actualCb(); return true; - } + }, }, end: { - value: ( - chunk?: Buffer | string | (() => void), - encoding?: BufferEncoding | (() => void), - cb?: () => void - ) => { + value: (chunk?: Buffer | string | (() => void), encoding?: BufferEncoding | (() => void), cb?: () => void) => { let actualChunk: Buffer | string | undefined; let actualEncoding: BufferEncoding | undefined; let actualCb: (() => void) | undefined; @@ -185,9 +176,7 @@ export class ProxyServer extends EventEmitter { } if (actualChunk) chunks.push( - Buffer.isBuffer(actualChunk) - ? actualChunk - : Buffer.from(actualChunk, actualEncoding as BufferEncoding) + Buffer.isBuffer(actualChunk) ? actualChunk : Buffer.from(actualChunk, actualEncoding as BufferEncoding) ); const body = Buffer.concat(chunks); const contentType = (headers['content-type'] ?? headers['Content-Type'] ?? '') as string; @@ -199,8 +188,8 @@ export class ProxyServer extends EventEmitter { res.writeHead(statusCode, headers); res.end(body, actualCb); } - } - } + }, + }, }) as ServerResponse; return wrapped; diff --git a/test/commands/webapp/_cleanup.nut.ts b/test/commands/webui/_cleanup.nut.ts similarity index 100% rename from test/commands/webapp/_cleanup.nut.ts rename to test/commands/webui/_cleanup.nut.ts diff --git a/test/commands/webapp/dev.nut.ts b/test/commands/webui/dev.nut.ts similarity index 84% rename from test/commands/webapp/dev.nut.ts rename to test/commands/webui/dev.nut.ts index b1cc3eb..2f140c0 100644 --- a/test/commands/webapp/dev.nut.ts +++ b/test/commands/webui/dev.nut.ts @@ -29,6 +29,7 @@ import { webappPath, ensureSfCli, authOrgViaUrl, + REAL_HOME, } from './helpers/webappProjectUtils.js'; /* ------------------------------------------------------------------ * @@ -37,7 +38,7 @@ import { * Validates flag-level parse errors that fire before any org or * * filesystem interaction. No credentials needed; always runs. * * ------------------------------------------------------------------ */ -describe('webapp dev NUTs — Tier 1 (no auth)', () => { +describe('webui dev NUTs — Tier 1 (no auth)', () => { let session: TestSession; before(async () => { @@ -51,7 +52,7 @@ describe('webapp dev NUTs — Tier 1 (no auth)', () => { // --target-org is declared as Flags.requiredOrg(). Running without it // must fail at parse time with NoDefaultEnvError before any other logic. it('should require --target-org', () => { - const result = execCmd('webapp dev --json', { + const result = execCmd('webui dev --json', { ensureExitCode: 1, cwd: session.dir, }); @@ -70,7 +71,7 @@ describe('webapp dev NUTs — Tier 1 (no auth)', () => { * * * Requires TESTKIT_AUTH_URL. Fails when absent (tests are mandatory). * * ------------------------------------------------------------------ */ -describe('webapp dev NUTs — Tier 2 CLI validation', () => { +describe('webui dev NUTs — Tier 2 CLI validation', () => { let session: TestSession; let targetOrg: string; @@ -92,11 +93,11 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { // ── Discovery errors ────────────────────────────────────────── - // Project has no webapplications folder at all → WebappNotFoundError. + // Project has no webui folder at all → WebappNotFoundError. it('should error when no webapp found (project only, no webapps)', () => { const projectDir = createProject(session, 'noWebappProject'); - const result = execCmd(`webapp dev --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -108,7 +109,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { it('should error when --name does not match any webapp', () => { const projectDir = createProjectWithWebapp(session, 'nameNotFound', 'realApp'); - const result = execCmd(`webapp dev --name NonExistent --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name NonExistent --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -120,11 +121,15 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { // Discovery treats this as ambiguous intent and rejects it. it('should error on --name conflict when inside a different webapp', () => { const projectDir = createProjectWithWebapp(session, 'nameConflict', 'appA'); - execSync('sf webapp generate --name appB', { cwd: projectDir, stdio: 'pipe' }); + execSync('sf template generate webui --name appB', { + cwd: projectDir, + stdio: 'pipe', + env: { ...process.env, HOME: REAL_HOME, USERPROFILE: REAL_HOME }, + }); const cwdInsideAppA = webappPath(projectDir, 'appA'); - const result = execCmd(`webapp dev --name appB --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name appB --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: cwdInsideAppA, }); @@ -132,12 +137,12 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { expect(result.jsonOutput?.name).to.equal('WebappNameConflictError'); }); - // webapplications/ folder exists but is empty → WebappNotFoundError. - it('should error when webapplications folder is empty', () => { + // webui/ folder exists but is empty → WebappNotFoundError. + it('should error when webui folder is empty', () => { const projectDir = createProject(session, 'emptyWebapps'); createEmptyWebappsDir(projectDir); - const result = execCmd(`webapp dev --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -145,12 +150,12 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { expect(result.jsonOutput?.name).to.equal('WebappNotFoundError'); }); - // webapplications/orphanApp/ exists but has no .webapplication-meta.xml → not a valid webapp. + // webui/orphanApp/ exists but has no .webapplication-meta.xml → not a valid webapp. it('should error when webapp dir has no .webapplication-meta.xml', () => { const projectDir = createProject(session, 'noMeta'); createWebappDirWithoutMeta(projectDir, 'orphanApp'); - const result = execCmd(`webapp dev --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -173,7 +178,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { dev: { url: 'http://localhost:5181' }, }); - const result = execCmd(`webapp dev --name appA --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name appA --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -192,7 +197,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { dev: { url: 'http://localhost:5183' }, }); - const result = execCmd(`webapp dev --name appB --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name appB --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -202,7 +207,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { // ── Auto-selection ──────────────────────────────────────────── - // When cwd is inside webapplications/myApp/, discovery auto-selects that + // When cwd is inside webui/myApp/, discovery auto-selects that // webapp without --name. The command proceeds past discovery and fails at // URL resolution (no dev server running) — confirming auto-select worked. it('should auto-select webapp when run from inside its directory', () => { @@ -217,7 +222,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { // No --name flag; cwd is inside the webapp directory. // Discovery auto-selects myApp, then the command fails at URL check // (nothing running on 5179). DevServerUrlError proves discovery succeeded. - const result = execCmd(`webapp dev --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: cwdInsideApp, }); @@ -225,7 +230,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { expect(result.jsonOutput?.name).to.equal('DevServerUrlError'); }); - // When multiple webapps exist and cwd is inside webapplications/appA/, + // When multiple webapps exist and cwd is inside webui/appA/, // discovery auto-selects appA without prompting. Proceeds past discovery // and fails at URL resolution — confirming auto-select works with multiple. it('should auto-select webapp when run from inside its directory (multiple webapps)', () => { @@ -240,7 +245,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { const cwdInsideAppA = webappPath(projectDir, 'appA'); - const result = execCmd(`webapp dev --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: cwdInsideAppA, }); @@ -255,7 +260,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { it('should error when --url is unreachable', () => { const projectDir = createProjectWithWebapp(session, 'urlUnreachable', 'myApp'); - const result = execCmd(`webapp dev --name myApp --url http://localhost:5179 --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name myApp --url http://localhost:5179 --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -272,7 +277,7 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { dev: { url: 'http://localhost:5179' }, }); - const result = execCmd(`webapp dev --name myApp --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name myApp --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); @@ -290,15 +295,12 @@ describe('webapp dev NUTs — Tier 2 CLI validation', () => { const projectDir = createProjectWithWebapp(session, 'noInstall', 'myApp'); const appDir = webappPath(projectDir, 'myApp'); - writeFileSync( - join(appDir, 'package.json'), - JSON.stringify({ name: 'test-webapp', scripts: { dev: 'vite' } }) - ); + writeFileSync(join(appDir, 'package.json'), JSON.stringify({ name: 'test-webapp', scripts: { dev: 'vite' } })); writeManifest(projectDir, 'myApp', { dev: { command: 'npm run dev' }, }); - const result = execCmd(`webapp dev --name myApp --target-org ${targetOrg} --json`, { + const result = execCmd(`webui dev --name myApp --target-org ${targetOrg} --json`, { ensureExitCode: 1, cwd: projectDir, }); diff --git a/test/commands/webapp/dev.test.ts b/test/commands/webui/dev.test.ts similarity index 99% rename from test/commands/webapp/dev.test.ts rename to test/commands/webui/dev.test.ts index ceb9668..91e314b 100644 --- a/test/commands/webapp/dev.test.ts +++ b/test/commands/webui/dev.test.ts @@ -19,7 +19,7 @@ import sinon from 'sinon'; import { TestContext } from '@salesforce/core/testSetup'; import type { WebAppManifest, WebAppDevResult } from '../../../src/config/types.js'; -describe('webapp:dev command integration', () => { +describe('webui:dev command integration', () => { const $$ = new TestContext(); afterEach(() => { diff --git a/test/commands/webapp/devPort.nut.ts b/test/commands/webui/devPort.nut.ts similarity index 98% rename from test/commands/webapp/devPort.nut.ts rename to test/commands/webui/devPort.nut.ts index 5cbff70..b71309b 100644 --- a/test/commands/webapp/devPort.nut.ts +++ b/test/commands/webui/devPort.nut.ts @@ -42,7 +42,7 @@ import { const DEV_PORT = 18_910; const PROXY_PORT = 18_920; -describe('webapp dev NUTs — Tier 2 port handling', function () { +describe('webui dev NUTs — Tier 2 port handling', function () { this.timeout(SUITE_TIMEOUT); let session: TestSession; diff --git a/test/commands/webapp/devWithUrl.nut.ts b/test/commands/webui/devWithUrl.nut.ts similarity index 97% rename from test/commands/webapp/devWithUrl.nut.ts rename to test/commands/webui/devWithUrl.nut.ts index 5c6d0a6..dedebc4 100644 --- a/test/commands/webapp/devWithUrl.nut.ts +++ b/test/commands/webui/devWithUrl.nut.ts @@ -50,7 +50,7 @@ const FULL_FLOW_PORT = 18_900; const PROXY_ONLY_PORT = 18_930; const VITE_PORT = 18_940; -describe('webapp dev NUTs — Tier 2 URL/proxy integration', function () { +describe('webui dev NUTs — Tier 2 URL/proxy integration', function () { this.timeout(SUITE_TIMEOUT); let session: TestSession; @@ -237,10 +237,14 @@ describe('webapp dev NUTs — Tier 2 URL/proxy integration', function () { handle = await spawnWebappDev( [ - '--name', 'myApp', - '--url', `http://localhost:${PROXY_ONLY_PORT + 3}`, - '--port', String(customProxyPort), - '--target-org', targetOrg, + '--name', + 'myApp', + '--url', + `http://localhost:${PROXY_ONLY_PORT + 3}`, + '--port', + String(customProxyPort), + '--target-org', + targetOrg, ], { cwd: projectDir, timeout: SPAWN_TIMEOUT } ); diff --git a/test/commands/webapp/helpers/devServerUtils.ts b/test/commands/webui/helpers/devServerUtils.ts similarity index 97% rename from test/commands/webapp/helpers/devServerUtils.ts rename to test/commands/webui/helpers/devServerUtils.ts index ce161cf..2ae845a 100644 --- a/test/commands/webapp/helpers/devServerUtils.ts +++ b/test/commands/webui/helpers/devServerUtils.ts @@ -50,7 +50,7 @@ export type WebappDevHandle = { }; /** - * Spawn `sf webapp dev` asynchronously and wait for the JSON URL line on stderr. + * Spawn `sf webui dev` asynchronously and wait for the JSON URL line on stderr. * * Uses `bin/dev.js` (same binary that `execCmd` uses) so we test the * local plugin code, not whatever is installed globally. @@ -59,7 +59,7 @@ export function spawnWebappDev(args: string[], options: { cwd: string; timeout?: const binDev = join(process.cwd(), 'bin', 'dev.js'); const proc = spawn( process.execPath, - ['--loader', 'ts-node/esm', '--no-warnings=ExperimentalWarning', binDev, 'webapp', 'dev', ...args], + ['--loader', 'ts-node/esm', '--no-warnings=ExperimentalWarning', binDev, 'webui', 'dev', ...args], { cwd: options.cwd, stdio: ['pipe', 'pipe', 'pipe'], @@ -140,7 +140,7 @@ export function spawnWebappDev(args: string[], options: { cwd: string; timeout?: proc.on('close', (code) => { clearTimeout(timeoutId); if (code !== null && code !== 0) { - reject(new Error(`webapp dev exited with code ${code}.\nstderr:\n${stderrData}`)); + reject(new Error(`webui dev exited with code ${code}.\nstderr:\n${stderrData}`)); } }); }); diff --git a/test/commands/webapp/helpers/webappProjectUtils.ts b/test/commands/webui/helpers/webappProjectUtils.ts similarity index 86% rename from test/commands/webapp/helpers/webappProjectUtils.ts rename to test/commands/webui/helpers/webappProjectUtils.ts index dee8dfa..0d40e8d 100644 --- a/test/commands/webapp/helpers/webappProjectUtils.ts +++ b/test/commands/webui/helpers/webappProjectUtils.ts @@ -16,19 +16,27 @@ import { execSync } from 'node:child_process'; import { mkdirSync, rmSync, writeFileSync } from 'node:fs'; +import { homedir } from 'node:os'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import type { TestSession } from '@salesforce/cli-plugins-testkit'; /** - * Relative path from project root to the webapplications folder. + * Real home directory captured at module load, before TestSession overrides process.env.HOME. + * Used when running `sf template generate webui` so the CLI finds linked plugin-templates + * (TestSession sets HOME to a temp dir, which hides linked plugins). + */ +export const REAL_HOME = homedir(); + +/** + * Relative path from project root to the webui folder. * Mirrors WEBAPPLICATIONS_RELATIVE_PATH in src/config/webappDiscovery.ts. */ -const WEBAPPS_PATH = join('force-app', 'main', 'default', 'webapplications'); +const WEBAPPS_PATH = join('force-app', 'main', 'default', 'webui'); /** * Resolve the absolute path to a webapp directory within a project. - * If `webAppName` is omitted, returns the webapplications folder itself. + * If `webAppName` is omitted, returns the webui folder itself. */ export function webappPath(projectDir: string, webAppName?: string): string { return webAppName ? join(projectDir, WEBAPPS_PATH, webAppName) : join(projectDir, WEBAPPS_PATH); @@ -91,14 +99,15 @@ export function createProject(session: TestSession, name: string): string { } /** - * Run `sf project generate` then `sf webapp generate --name ` inside + * Run `sf project generate` then `sf template generate webui --name ` inside * the project. Returns the absolute path to the generated project root. */ export function createProjectWithWebapp(session: TestSession, projectName: string, webAppName: string): string { const projectDir = createProject(session, projectName); - execSync(`sf webapp generate --name ${webAppName}`, { + execSync(`sf template generate webui --name ${webAppName}`, { cwd: projectDir, stdio: 'pipe', + env: { ...process.env, HOME: REAL_HOME, USERPROFILE: REAL_HOME }, }); return projectDir; } @@ -114,17 +123,18 @@ export function createProjectWithMultipleWebapps( ): string { const projectDir = createProject(session, projectName); for (const name of webAppNames) { - execSync(`sf webapp generate --name ${name}`, { + execSync(`sf template generate webui --name ${name}`, { cwd: projectDir, stdio: 'pipe', + env: { ...process.env, HOME: REAL_HOME, USERPROFILE: REAL_HOME }, }); } return projectDir; } /** - * Create the `webapplications/` directory (empty — no webapps inside). - * Used to test "empty webapplications folder" scenario. + * Create the `webui/` directory (empty — no webapps inside). + * Used to test "empty webui folder" scenario. */ export function createEmptyWebappsDir(projectDir: string): void { mkdirSync(webappPath(projectDir), { recursive: true }); diff --git a/test/config/webappDiscovery.test.ts b/test/config/webappDiscovery.test.ts index bc9d0a0..534b382 100644 --- a/test/config/webappDiscovery.test.ts +++ b/test/config/webappDiscovery.test.ts @@ -23,8 +23,8 @@ import { DEFAULT_DEV_COMMAND, discoverWebapp } from '../../src/config/webappDisc describe('webappDiscovery', () => { const testDir = join(process.cwd(), '.test-webapp-discovery'); - // Standard SFDX webapplications path - const sfdxWebappsPath = join(testDir, 'force-app', 'main', 'default', 'webapplications'); + // Standard SFDX webui path + const sfdxWebappsPath = join(testDir, 'force-app', 'main', 'default', 'webui'); // Store original resolveProjectPath let originalResolveProjectPath: typeof SfProject.resolveProjectPath; @@ -120,7 +120,7 @@ describe('webappDiscovery', () => { } catch (error) { expect(error).to.be.instanceOf(SfError); expect((error as SfError).name).to.equal('WebappNotFoundError'); - expect((error as SfError).message).to.include('No webapplications folder found in the SFDX project'); + expect((error as SfError).message).to.include('No webui folder found in the SFDX project'); } }); @@ -167,7 +167,7 @@ describe('webappDiscovery', () => { }); it('should auto-select webapp when inside its folder', async () => { - const webappsPath = join(testDir, 'webapplications'); + const webappsPath = join(testDir, 'webui'); mkdirSync(webappsPath, { recursive: true }); const myAppPath = createWebapp(webappsPath, 'my-app'); createWebapp(webappsPath, 'other-app'); @@ -179,7 +179,7 @@ describe('webappDiscovery', () => { }); it('should auto-select webapp when inside subfolder', async () => { - const webappsPath = join(testDir, 'webapplications'); + const webappsPath = join(testDir, 'webui'); mkdirSync(webappsPath, { recursive: true }); const myAppPath = createWebapp(webappsPath, 'my-app'); const srcPath = join(myAppPath, 'src'); @@ -193,7 +193,7 @@ describe('webappDiscovery', () => { }); it('should use meta.xml name (manifest.name is not used)', async () => { - const webappsPath = join(testDir, 'webapplications'); + const webappsPath = join(testDir, 'webui'); mkdirSync(webappsPath, { recursive: true }); const myAppPath = createWebapp(webappsPath, 'folder-name', { name: 'ManifestName' }); createWebapp(webappsPath, 'other-app'); @@ -230,7 +230,7 @@ describe('webappDiscovery', () => { }); it('should throw error when --name conflicts with current webapp directory', async () => { - const webappsPath = join(testDir, 'webapplications'); + const webappsPath = join(testDir, 'webui'); mkdirSync(webappsPath, { recursive: true }); const currentAppPath = createWebapp(webappsPath, 'current-app'); createWebapp(webappsPath, 'other-app'); @@ -248,7 +248,7 @@ describe('webappDiscovery', () => { }); it('should allow --name matching current webapp directory', async () => { - const webappsPath = join(testDir, 'webapplications'); + const webappsPath = join(testDir, 'webui'); mkdirSync(webappsPath, { recursive: true }); const currentAppPath = createWebapp(webappsPath, 'current-app'); createWebapp(webappsPath, 'other-app'); @@ -296,7 +296,7 @@ describe('webappDiscovery', () => { it('should discover webapps from multiple package directories', async () => { // Create project with two packages: force-app and packages/einstein - const einsteinWebappsPath = join(testDir, 'packages', 'einstein', 'main', 'default', 'webapplications'); + const einsteinWebappsPath = join(testDir, 'packages', 'einstein', 'main', 'default', 'webui'); mkdirSync(einsteinWebappsPath, { recursive: true }); setupSfdxProject([ { path: 'force-app', default: true },