mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-13 15:35:20 +01:00
Merge branch 'main' into copilot/fix-tooltip-markdown-syntax
This commit is contained in:
@@ -18,8 +18,6 @@
|
||||
**/extensions/terminal-suggest/src/shell/fishBuiltinsCache.ts
|
||||
**/extensions/terminal-suggest/third_party/**
|
||||
**/extensions/typescript-language-features/test-workspace/**
|
||||
**/extensions/typescript-language-features/extension.webpack.config.js
|
||||
**/extensions/typescript-language-features/extension-browser.webpack.config.js
|
||||
**/extensions/typescript-language-features/package-manager/node-maintainer/**
|
||||
**/extensions/vscode-api-tests/testWorkspace/**
|
||||
**/extensions/vscode-api-tests/testWorkspace2/**
|
||||
|
||||
@@ -26,6 +26,7 @@ src/vs/base/browser/ui/tree/** @joaomoreno @benibenj
|
||||
# Platform
|
||||
src/vs/platform/auxiliaryWindow/** @bpasero
|
||||
src/vs/platform/backup/** @bpasero
|
||||
src/vs/platform/browserView/** @kycutler @jruales
|
||||
src/vs/platform/dialogs/** @bpasero
|
||||
src/vs/platform/editor/** @bpasero
|
||||
src/vs/platform/environment/** @bpasero
|
||||
@@ -65,6 +66,7 @@ src/vs/code/** @bpasero @deepak1556
|
||||
src/vs/workbench/services/activity/** @bpasero
|
||||
src/vs/workbench/services/authentication/** @TylerLeonhardt
|
||||
src/vs/workbench/services/auxiliaryWindow/** @bpasero
|
||||
src/vs/workbench/services/browserView/** @kycutler @jruales
|
||||
src/vs/workbench/services/contextmenu/** @bpasero
|
||||
src/vs/workbench/services/dialogs/** @alexr00 @bpasero
|
||||
src/vs/workbench/services/editor/** @bpasero
|
||||
@@ -97,6 +99,7 @@ src/vs/workbench/electron-browser/** @bpasero
|
||||
|
||||
# Workbench Contributions
|
||||
src/vs/workbench/contrib/authentication/** @TylerLeonhardt
|
||||
src/vs/workbench/contrib/browserView/** @kycutler @jruales
|
||||
src/vs/workbench/contrib/files/** @bpasero
|
||||
src/vs/workbench/contrib/chat/browser/chatListRenderer.ts @roblourens
|
||||
src/vs/workbench/contrib/localization/** @TylerLeonhardt
|
||||
|
||||
@@ -42,3 +42,7 @@ Your response should include:
|
||||
- Interpretation and analysis of the results
|
||||
- References to specific documentation files when applicable
|
||||
- Additional context or insights from the telemetry data
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
If the connection to the Kusto cluster is timing out consistently, stop and ask the user to check whether they are connected to Azure VPN.
|
||||
|
||||
@@ -24,6 +24,7 @@ Visual Studio Code is built with a layered architecture using TypeScript, web AP
|
||||
- `workbench/api/` - Extension host and VS Code API implementation
|
||||
- `src/vs/code/` - Electron main process specific implementation
|
||||
- `src/vs/server/` - Server specific implementation
|
||||
- `src/vs/sessions/` - Agent sessions window, a dedicated workbench layer for agentic workflows (sits alongside `vs/workbench`, may import from it but not vice versa)
|
||||
|
||||
The core architecture follows these principles:
|
||||
- **Layered architecture** - from `base`, `platform`, `editor`, to `workbench`
|
||||
@@ -49,15 +50,16 @@ Each extension follows the standard VS Code extension structure with `package.js
|
||||
|
||||
## Validating TypeScript changes
|
||||
|
||||
MANDATORY: Always check the `VS Code - Build` watch task output via #runTasks/getTaskOutput for compilation errors before running ANY script or declaring work complete, then fix all compilation errors before moving forward.
|
||||
MANDATORY: Always check for compilation errors before running any tests or validation scripts, or declaring work complete, then fix all compilation errors before moving forward.
|
||||
|
||||
- NEVER run tests if there are compilation errors
|
||||
- NEVER use `npm run compile` to compile TypeScript files but call #runTasks/getTaskOutput instead
|
||||
- NEVER use `npm run compile` to compile TypeScript files
|
||||
|
||||
### TypeScript compilation steps
|
||||
- Monitor the `VS Code - Build` task outputs for real-time compilation errors as you make changes
|
||||
- This task runs `Core - Build` and `Ext - Build` to incrementally compile VS Code TypeScript sources and built-in extensions
|
||||
- Start the task if it's not already running in the background
|
||||
- If the `#runTasks/getTaskOutput` tool is available, check the `VS Code - Build` watch task output for compilation errors. This task runs `Core - Build` and `Ext - Build` to incrementally compile VS Code TypeScript sources and built-in extensions. Start the task if it's not already running in the background.
|
||||
- If the tool is not available (e.g. in CLI environments) and you only changed code under `src/`, run `npm run compile-check-ts-native` after making changes to type-check the main VS Code sources (it validates `./src/tsconfig.json`).
|
||||
- If you changed built-in extensions under `extensions/` and the tool is not available, run the corresponding gulp task `gulp compile-extensions` instead so that TypeScript errors in extensions are also reported.
|
||||
- For TypeScript changes in the `build` folder, you can simply run `npm run typecheck` in the `build` folder.
|
||||
|
||||
### TypeScript validation steps
|
||||
- Use the run test tool if you need to run tests. If that tool is not available, then you can use `scripts/test.sh` (or `scripts\test.bat` on Windows) for unit tests (add `--grep <pattern>` to filter tests) or `scripts/test-integration.sh` (or `scripts\test-integration.bat` on Windows) for integration tests (integration tests end with .integrationTest.ts or are in /extensions/).
|
||||
@@ -134,6 +136,7 @@ function f(x: number, y: string): void { }
|
||||
- Prefer regex capture groups with names over numbered capture groups.
|
||||
- If you create any temporary new files, scripts, or helper files for iteration, clean up these files by removing them at the end of the task
|
||||
- Never duplicate imports. Always reuse existing imports if they are present.
|
||||
- When removing an import, do not leave behind blank lines where the import was. Ensure the surrounding code remains compact.
|
||||
- Do not use `any` or `unknown` as the type for variables, parameters, or return values unless absolutely necessary. If they need type annotations, they should have proper types or interfaces defined.
|
||||
- When adding file watching, prefer correlated file watchers (via fileService.createWatcher) to shared ones.
|
||||
- When adding tooltips to UI elements, prefer the use of IHoverService service.
|
||||
|
||||
@@ -8,3 +8,17 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
allow:
|
||||
- dependency-name: "@vscode/component-explorer"
|
||||
- dependency-name: "@vscode/component-explorer-cli"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/build/vite"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
allow:
|
||||
- dependency-name: "@vscode/component-explorer"
|
||||
- dependency-name: "@vscode/component-explorer-vite-plugin"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": "if [ -f ~/.vscode-worktree-setup ]; then nohup bash -c 'npm ci && npm run compile' > /tmp/worktree-setup-$(date +%Y-%m-%d_%H-%M-%S).log 2>&1 & fi",
|
||||
"powershell": "if (Test-Path \"$env:USERPROFILE\\.vscode-worktree-setup\") { $log = \"$env:TEMP\\worktree-setup-$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').log\"; $dir = $PWD.Path; Start-Job -ScriptBlock { param($d, $l) Set-Location $d; & { npm ci; if ($LASTEXITCODE -eq 0) { npm run compile } } *> $l } -ArgumentList $dir, $log | Out-Null }"
|
||||
}
|
||||
],
|
||||
"sessionEnd": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ""
|
||||
}
|
||||
],
|
||||
"agentStop": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ""
|
||||
}
|
||||
],
|
||||
"userPromptSubmitted": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ""
|
||||
}
|
||||
],
|
||||
"preToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ""
|
||||
}
|
||||
],
|
||||
"postToolUse": [
|
||||
{
|
||||
"type": "command",
|
||||
"bash": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ description: Kusto exploration and telemetry analysis instructions
|
||||
|
||||
When performing Kusto queries, telemetry analysis, or data exploration tasks for VS Code, consult the comprehensive Kusto instructions located at:
|
||||
|
||||
**[kusto-vscode-instructions.md](../../../vscode-internalbacklog/instructions/kusto/kusto-vscode-instructions.md)**
|
||||
**[kusto-vscode-instructions.md](../../../vscode-tools/.github/skills/kusto-telemetry/kusto-vscode.instructions.md)**
|
||||
|
||||
These instructions contain valuable information about:
|
||||
- Available Kusto clusters and databases for VS Code telemetry
|
||||
@@ -16,4 +16,4 @@ These instructions contain valuable information about:
|
||||
|
||||
Reading these instructions before writing Kusto queries will help you write more accurate and efficient queries, avoid common pitfalls, and leverage existing knowledge about VS Code's telemetry infrastructure.
|
||||
|
||||
(Make sure to have the main branch of vscode-internalbacklog up to date in case there are problems).
|
||||
(Make sure to have the main branch of vscode-tools up to date in case there are problems and the repository cloned from https://github.com/microsoft/vscode-tools).
|
||||
|
||||
@@ -45,7 +45,7 @@ When proposing or implementing changes, follow these rules from the spec:
|
||||
4. **New parts go in the right section** — Any new parts should be added to the horizontal branch alongside Chat Bar and Auxiliary Bar
|
||||
5. **Preserve no-op methods** — Unsupported features (zen mode, centered layout, etc.) should remain as no-ops, not throw errors
|
||||
6. **Handle pane composite lifecycle** — When hiding/showing parts, manage the associated pane composites
|
||||
7. **Use agent session parts** — New part functionality goes in the agent session part classes (`SidebarPart`, `AuxiliaryBarPart`, `PanelPart`, `ChatBarPart`), not the standard workbench parts
|
||||
7. **Use agent session parts** — New part functionality goes in the agent session part classes (`SidebarPart`, `AuxiliaryBarPart`, `PanelPart`, `ChatBarPart`, `ProjectBarPart`), not the standard workbench parts
|
||||
8. **Use separate storage keys** — Agent session parts use their own storage keys (prefixed with `workbench.agentsession.` or `workbench.chatbar.`) to avoid conflicts with regular workbench state
|
||||
9. **Use agent session menu IDs** — Actions should use `Menus.*` menu IDs (from `sessions/browser/menus.ts`), not shared `MenuId.*` constants
|
||||
|
||||
@@ -53,20 +53,24 @@ When proposing or implementing changes, follow these rules from the spec:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `sessions/LAYOUT.md` | Authoritative specification |
|
||||
| `sessions/LAYOUT.md` | Authoritative layout specification |
|
||||
| `sessions/browser/workbench.ts` | Main layout implementation (`Workbench` class) |
|
||||
| `sessions/browser/menus.ts` | Agent sessions menu IDs (`Menus` export) |
|
||||
| `sessions/browser/layoutActions.ts` | Layout actions (toggle sidebar, panel, secondary sidebar) |
|
||||
| `sessions/browser/paneCompositePartService.ts` | `AgenticPaneCompositePartService` |
|
||||
| `sessions/browser/style.css` | Layout-specific styles |
|
||||
| `sessions/browser/parts/` | Agent session part implementations |
|
||||
| `sessions/browser/media/style.css` | Layout-specific styles |
|
||||
| `sessions/browser/parts/parts.ts` | `AgenticParts` enum |
|
||||
| `sessions/browser/parts/titlebarPart.ts` | Titlebar part, MainTitlebarPart, AuxiliaryTitlebarPart, TitleService |
|
||||
| `sessions/browser/parts/sidebarPart.ts` | Sidebar part (with footer) |
|
||||
| `sessions/browser/parts/sidebarPart.ts` | Sidebar part (with footer and macOS traffic light spacer) |
|
||||
| `sessions/browser/parts/chatBarPart.ts` | Chat Bar part |
|
||||
| `sessions/browser/widget/` | Agent sessions chat widget |
|
||||
| `sessions/browser/parts/auxiliaryBarPart.ts` | Auxiliary Bar part (with run script dropdown) |
|
||||
| `sessions/browser/parts/panelPart.ts` | Panel part |
|
||||
| `sessions/browser/parts/projectBarPart.ts` | Project Bar part (folder entries, icon customization) |
|
||||
| `sessions/contrib/configuration/browser/configuration.contribution.ts` | Sets `workbench.editor.useModal` to `'all'` for modal editor overlay |
|
||||
| `sessions/contrib/sessions/browser/sessionsTitleBarWidget.ts` | Title bar widget and session picker |
|
||||
| `sessions/contrib/chat/browser/runScriptAction.ts` | Run script contribution |
|
||||
| `sessions/contrib/chat/browser/runScriptAction.ts` | Run script split button for titlebar |
|
||||
| `sessions/contrib/accountMenu/browser/account.contribution.ts` | Account widget for sidebar footer |
|
||||
| `sessions/electron-browser/parts/titlebarPart.ts` | Desktop (Electron) titlebar part |
|
||||
|
||||
## 5. Testing Changes
|
||||
|
||||
|
||||
@@ -66,21 +66,24 @@ Use the [queue command](./azure-pipeline.ts) to queue a validation build:
|
||||
|
||||
```bash
|
||||
# Queue a build on the current branch
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
|
||||
# Queue with a specific source branch
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue --branch my-feature-branch
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue --branch my-feature-branch
|
||||
|
||||
# Queue with custom variables (e.g., to skip certain stages)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue --variables "SKIP_TESTS=true"
|
||||
# Queue with custom parameters
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue --parameter "VSCODE_BUILD_WEB=false" --parameter "VSCODE_PUBLISH=false"
|
||||
|
||||
# Parameter value with spaces
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue --parameter "VSCODE_BUILD_TYPE=Product Build"
|
||||
```
|
||||
|
||||
> **Important**: Before queueing a new build, cancel any previous builds on the same branch that you no longer need. This frees up build agents and reduces resource waste:
|
||||
> ```bash
|
||||
> # Find the build ID from status, then cancel it
|
||||
> node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
> node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id>
|
||||
> node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
> node .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
> node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id>
|
||||
> node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
> ```
|
||||
|
||||
### Script Options
|
||||
@@ -89,9 +92,43 @@ node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts
|
||||
|--------|-------------|
|
||||
| `--branch <name>` | Source branch to build (default: current git branch) |
|
||||
| `--definition <id>` | Pipeline definition ID (default: 111) |
|
||||
| `--variables <vars>` | Pipeline variables in `KEY=value` format, space-separated |
|
||||
| `--parameter <entry>` | Pipeline parameter in `KEY=value` format (repeatable) |
|
||||
| `--parameters <list>` | Space-separated parameters in `KEY=value KEY2=value2` format |
|
||||
| `--dry-run` | Print the command without executing |
|
||||
|
||||
### Product Build Queue Parameters (`build/azure-pipelines/product-build.yml`)
|
||||
|
||||
| Name | Type | Default | Allowed Values | Description |
|
||||
|------|------|---------|----------------|-------------|
|
||||
| `VSCODE_QUALITY` | string | `insider` | `exploration`, `insider`, `stable` | Build quality channel |
|
||||
| `VSCODE_BUILD_TYPE` | string | `Product Build` | `Product`, `CI` | Build mode for Product vs CI |
|
||||
| `NPM_REGISTRY` | string | `https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/npm/registry/` | any URL | Custom npm registry |
|
||||
| `CARGO_REGISTRY` | string | `sparse+https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/Cargo/index/` | any URL | Custom Cargo registry |
|
||||
| `VSCODE_BUILD_WIN32` | boolean | `true` | `true`, `false` | Build Windows x64 |
|
||||
| `VSCODE_BUILD_WIN32_ARM64` | boolean | `true` | `true`, `false` | Build Windows arm64 |
|
||||
| `VSCODE_BUILD_LINUX` | boolean | `true` | `true`, `false` | Build Linux x64 |
|
||||
| `VSCODE_BUILD_LINUX_SNAP` | boolean | `true` | `true`, `false` | Build Linux x64 Snap |
|
||||
| `VSCODE_BUILD_LINUX_ARM64` | boolean | `true` | `true`, `false` | Build Linux arm64 |
|
||||
| `VSCODE_BUILD_LINUX_ARMHF` | boolean | `true` | `true`, `false` | Build Linux armhf |
|
||||
| `VSCODE_BUILD_ALPINE` | boolean | `true` | `true`, `false` | Build Alpine x64 |
|
||||
| `VSCODE_BUILD_ALPINE_ARM64` | boolean | `true` | `true`, `false` | Build Alpine arm64 |
|
||||
| `VSCODE_BUILD_MACOS` | boolean | `true` | `true`, `false` | Build macOS x64 |
|
||||
| `VSCODE_BUILD_MACOS_ARM64` | boolean | `true` | `true`, `false` | Build macOS arm64 |
|
||||
| `VSCODE_BUILD_MACOS_UNIVERSAL` | boolean | `true` | `true`, `false` | Build macOS universal (requires both macOS arches) |
|
||||
| `VSCODE_BUILD_WEB` | boolean | `true` | `true`, `false` | Build Web artifacts |
|
||||
| `VSCODE_PUBLISH` | boolean | `true` | `true`, `false` | Publish to builds.code.visualstudio.com |
|
||||
| `VSCODE_RELEASE` | boolean | `false` | `true`, `false` | Trigger release flow if successful |
|
||||
| `VSCODE_STEP_ON_IT` | boolean | `false` | `true`, `false` | Skip tests |
|
||||
|
||||
Example: run a quick CI-oriented validation with minimal publish/release side effects:
|
||||
|
||||
```bash
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue \
|
||||
--parameter "VSCODE_BUILD_TYPE=CI Build" \
|
||||
--parameter "VSCODE_PUBLISH=false" \
|
||||
--parameter "VSCODE_RELEASE=false"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checking Build Status
|
||||
@@ -99,17 +136,17 @@ node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts
|
||||
Use the [status command](./azure-pipeline.ts) to monitor a running build:
|
||||
|
||||
```bash
|
||||
# Get status of the most recent build on your branch
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
# Get status of the most recent builds
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
|
||||
# Get overview of a specific build by ID
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456
|
||||
|
||||
# Watch build status (refreshes every 30 seconds)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
|
||||
# Watch with custom interval (60 seconds)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --watch 60
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --watch 60
|
||||
```
|
||||
|
||||
### Script Options
|
||||
@@ -133,10 +170,10 @@ Use the [cancel command](./azure-pipeline.ts) to stop a running build:
|
||||
|
||||
```bash
|
||||
# Cancel a build by ID (use status command to find IDs)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456
|
||||
|
||||
# Dry run (show what would be cancelled)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456 --dry-run
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456 --dry-run
|
||||
```
|
||||
|
||||
### Script Options
|
||||
@@ -149,6 +186,44 @@ node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts
|
||||
|
||||
---
|
||||
|
||||
## Testing Pipeline Changes
|
||||
|
||||
When the user asks to **test changes in an Azure Pipelines build**, follow this workflow:
|
||||
|
||||
1. **Queue a new build** on the current branch
|
||||
2. **Poll for completion** by periodically checking the build status until it finishes
|
||||
|
||||
### Polling for Build Completion
|
||||
|
||||
Use a shell loop with `sleep` to poll the build status. The `sleep` command works on all major operating systems:
|
||||
|
||||
```bash
|
||||
# Queue the build and note the build ID from output (e.g., 123456)
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
|
||||
# Poll every 60 seconds until complete (works on macOS, Linux, and Windows with Git Bash/WSL)
|
||||
# Replace <BUILD_ID> with the actual build ID from the queue command
|
||||
while true; do
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id <BUILD_ID> --json 2>/dev/null | grep -q '"status": "completed"' && break
|
||||
sleep 60
|
||||
done
|
||||
|
||||
# Check final result
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id <BUILD_ID>
|
||||
```
|
||||
|
||||
Alternatively, use the built-in `--watch` flag which handles polling automatically:
|
||||
|
||||
```bash
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
# Use the build ID returned by the queue command
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id <BUILD_ID> --watch
|
||||
```
|
||||
|
||||
> **Note**: The `--watch` flag polls every 30 seconds by default. Use `--watch 60` for a 60-second interval to reduce API calls.
|
||||
|
||||
---
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### 1. Quick Pipeline Validation
|
||||
@@ -159,45 +234,50 @@ git add -A && git commit -m "test: pipeline changes"
|
||||
git push origin HEAD
|
||||
|
||||
# Check for any previous builds on this branch and cancel if needed
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id> # if there's an active build
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id> # if there's an active build
|
||||
|
||||
# Queue and watch the new build
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
```
|
||||
|
||||
### 2. Investigate a Build
|
||||
|
||||
```bash
|
||||
# Get overview of a build (shows stages, artifacts, and log IDs)
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456
|
||||
|
||||
# Download a specific log for deeper inspection
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456 --download-log 5
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456 --download-log 5
|
||||
|
||||
# Download an artifact
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456 --download-artifact unsigned_vscode_cli_win32_x64_cli
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id 123456 --download-artifact unsigned_vscode_cli_win32_x64_cli
|
||||
```
|
||||
|
||||
### 3. Test with Modified Variables
|
||||
### 3. Test with Modified Parameters
|
||||
|
||||
```bash
|
||||
# Skip expensive stages during validation
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue --variables "VSCODE_BUILD_SKIP_INTEGRATION_TESTS=true"
|
||||
# Customize build matrix for quicker validation
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue \
|
||||
--parameter "VSCODE_BUILD_TYPE=CI Build" \
|
||||
--parameter "VSCODE_BUILD_WEB=false" \
|
||||
--parameter "VSCODE_BUILD_ALPINE=false" \
|
||||
--parameter "VSCODE_BUILD_ALPINE_ARM64=false" \
|
||||
--parameter "VSCODE_PUBLISH=false"
|
||||
```
|
||||
|
||||
### 4. Cancel a Running Build
|
||||
|
||||
```bash
|
||||
# First, find the build ID
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
|
||||
# Cancel a specific build by ID
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456
|
||||
|
||||
# Dry run to see what would be cancelled
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456 --dry-run
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id 123456 --dry-run
|
||||
```
|
||||
|
||||
### 5. Iterate on Pipeline Changes
|
||||
@@ -210,12 +290,12 @@ git add -A && git commit --amend --no-edit
|
||||
git push --force-with-lease origin HEAD
|
||||
|
||||
# Find the outdated build ID and cancel it
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id>
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts cancel --build-id <id>
|
||||
|
||||
# Queue a fresh build and monitor
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts queue
|
||||
node .github/skills/azure-pipelines/azure-pipeline.ts status --watch
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* A unified command-line tool for managing Azure Pipeline builds.
|
||||
*
|
||||
* Usage:
|
||||
* node --experimental-strip-types azure-pipeline.ts <command> [options]
|
||||
* node azure-pipeline.ts <command> [options]
|
||||
*
|
||||
* Commands:
|
||||
* queue - Queue a new pipeline build
|
||||
@@ -38,8 +38,8 @@ const NUMERIC_ID_PATTERN = /^\d+$/;
|
||||
const MAX_ID_LENGTH = 15;
|
||||
const BRANCH_PATTERN = /^[a-zA-Z0-9_\-./]+$/;
|
||||
const MAX_BRANCH_LENGTH = 256;
|
||||
const VARIABLE_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*=[a-zA-Z0-9_\-./: ]*$/;
|
||||
const MAX_VARIABLE_LENGTH = 256;
|
||||
const PARAMETER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*=[a-zA-Z0-9_\-./: +]*$/;
|
||||
const MAX_PARAMETER_LENGTH = 256;
|
||||
const ARTIFACT_NAME_PATTERN = /^[a-zA-Z0-9_\-.]+$/;
|
||||
const MAX_ARTIFACT_NAME_LENGTH = 256;
|
||||
const MIN_WATCH_INTERVAL = 5;
|
||||
@@ -88,7 +88,7 @@ interface Artifact {
|
||||
interface QueueArgs {
|
||||
branch: string;
|
||||
definitionId: string;
|
||||
variables: string;
|
||||
parameters: string[];
|
||||
dryRun: boolean;
|
||||
help: boolean;
|
||||
}
|
||||
@@ -159,19 +159,18 @@ function validateBranch(value: string): void {
|
||||
}
|
||||
}
|
||||
|
||||
function validateVariables(value: string): void {
|
||||
if (!value) {
|
||||
function validateParameters(values: string[]): void {
|
||||
if (!values.length) {
|
||||
return;
|
||||
}
|
||||
const vars = value.split(' ').filter(v => v.length > 0);
|
||||
for (const v of vars) {
|
||||
if (v.length > MAX_VARIABLE_LENGTH) {
|
||||
console.error(colors.red(`Error: Variable '${v.substring(0, 20)}...' is too long (max ${MAX_VARIABLE_LENGTH} characters)`));
|
||||
for (const parameter of values) {
|
||||
if (parameter.length > MAX_PARAMETER_LENGTH) {
|
||||
console.error(colors.red(`Error: Parameter '${parameter.substring(0, 20)}...' is too long (max ${MAX_PARAMETER_LENGTH} characters)`));
|
||||
process.exit(1);
|
||||
}
|
||||
if (!VARIABLE_PATTERN.test(v)) {
|
||||
console.error(colors.red(`Error: Invalid variable format '${v}'`));
|
||||
console.log('Expected format: KEY=value (alphanumeric, underscores, hyphens, dots, slashes, colons, spaces in value)');
|
||||
if (!PARAMETER_PATTERN.test(parameter)) {
|
||||
console.error(colors.red(`Error: Invalid parameter format '${parameter}'`));
|
||||
console.log('Expected format: KEY=value (alphanumeric, underscores, hyphens, dots, slashes, colons, plus signs, spaces in value)');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -612,7 +611,7 @@ class AzureDevOpsClient {
|
||||
return JSON.parse(result);
|
||||
}
|
||||
|
||||
async queueBuild(definitionId: string, branch: string, variables?: string): Promise<Build> {
|
||||
async queueBuild(definitionId: string, branch: string, parameters: string[] = []): Promise<Build> {
|
||||
const args = [
|
||||
'pipelines', 'run',
|
||||
'--organization', this.organization,
|
||||
@@ -621,8 +620,8 @@ class AzureDevOpsClient {
|
||||
'--branch', branch,
|
||||
];
|
||||
|
||||
if (variables) {
|
||||
args.push('--variables', ...variables.split(' '));
|
||||
if (parameters.length > 0) {
|
||||
args.push('--parameters', ...parameters);
|
||||
}
|
||||
|
||||
args.push('--output', 'json');
|
||||
@@ -771,7 +770,7 @@ class AzureDevOpsClient {
|
||||
// ============================================================================
|
||||
|
||||
function printQueueUsage(): void {
|
||||
const scriptName = 'node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue';
|
||||
const scriptName = 'node .github/skills/azure-pipelines/azure-pipeline.ts queue';
|
||||
console.log(`Usage: ${scriptName} [options]`);
|
||||
console.log('');
|
||||
console.log('Queue an Azure DevOps pipeline build for VS Code.');
|
||||
@@ -779,21 +778,23 @@ function printQueueUsage(): void {
|
||||
console.log('Options:');
|
||||
console.log(' --branch <name> Source branch to build (default: current git branch)');
|
||||
console.log(' --definition <id> Pipeline definition ID (default: 111)');
|
||||
console.log(' --variables <vars> Pipeline variables in "KEY=value KEY2=value2" format');
|
||||
console.log(' --parameter <entry> Pipeline parameter in "KEY=value" format (repeatable)');
|
||||
console.log(' --parameters <list> Space-separated parameter list in "KEY=value KEY2=value2" format');
|
||||
console.log(' --dry-run Print the command without executing');
|
||||
console.log(' --help Show this help message');
|
||||
console.log('');
|
||||
console.log('Examples:');
|
||||
console.log(` ${scriptName} # Queue build on current branch`);
|
||||
console.log(` ${scriptName} --branch my-feature # Queue build on specific branch`);
|
||||
console.log(` ${scriptName} --variables "SKIP_TESTS=true" # Queue with custom variables`);
|
||||
console.log(` ${scriptName} --parameter "VSCODE_BUILD_WEB=false" --parameter "VSCODE_PUBLISH=false"`);
|
||||
console.log(` ${scriptName} --parameter "VSCODE_BUILD_TYPE=Product Build" # Parameter values with spaces`);
|
||||
}
|
||||
|
||||
function parseQueueArgs(args: string[]): QueueArgs {
|
||||
const result: QueueArgs = {
|
||||
branch: '',
|
||||
definitionId: DEFAULT_DEFINITION_ID,
|
||||
variables: '',
|
||||
parameters: [],
|
||||
dryRun: false,
|
||||
help: false,
|
||||
};
|
||||
@@ -807,8 +808,15 @@ function parseQueueArgs(args: string[]): QueueArgs {
|
||||
case '--definition':
|
||||
result.definitionId = args[++i] || DEFAULT_DEFINITION_ID;
|
||||
break;
|
||||
case '--variables':
|
||||
result.variables = args[++i] || '';
|
||||
case '--parameter': {
|
||||
const parameter = args[++i] || '';
|
||||
if (parameter) {
|
||||
result.parameters.push(parameter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '--parameters':
|
||||
result.parameters.push(...(args[++i] || '').split(' ').filter(v => v.length > 0));
|
||||
break;
|
||||
case '--dry-run':
|
||||
result.dryRun = true;
|
||||
@@ -829,7 +837,7 @@ function parseQueueArgs(args: string[]): QueueArgs {
|
||||
function validateQueueArgs(args: QueueArgs): void {
|
||||
validateNumericId(args.definitionId, '--definition');
|
||||
validateBranch(args.branch);
|
||||
validateVariables(args.variables);
|
||||
validateParameters(args.parameters);
|
||||
}
|
||||
|
||||
async function runQueueCommand(args: string[]): Promise<void> {
|
||||
@@ -860,8 +868,8 @@ async function runQueueCommand(args: string[]): Promise<void> {
|
||||
console.log(`Project: ${colors.green(PROJECT)}`);
|
||||
console.log(`Definition: ${colors.green(parsedArgs.definitionId)}`);
|
||||
console.log(`Branch: ${colors.green(branch)}`);
|
||||
if (parsedArgs.variables) {
|
||||
console.log(`Variables: ${colors.green(parsedArgs.variables)}`);
|
||||
if (parsedArgs.parameters.length > 0) {
|
||||
console.log(`Parameters: ${colors.green(parsedArgs.parameters.join(' '))}`);
|
||||
}
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('');
|
||||
@@ -875,8 +883,8 @@ async function runQueueCommand(args: string[]): Promise<void> {
|
||||
'--id', parsedArgs.definitionId,
|
||||
'--branch', branch,
|
||||
];
|
||||
if (parsedArgs.variables) {
|
||||
cmdArgs.push('--variables', ...parsedArgs.variables.split(' '));
|
||||
if (parsedArgs.parameters.length > 0) {
|
||||
cmdArgs.push('--parameters', ...parsedArgs.parameters);
|
||||
}
|
||||
cmdArgs.push('--output', 'json');
|
||||
console.log(`az ${cmdArgs.join(' ')}`);
|
||||
@@ -887,7 +895,7 @@ async function runQueueCommand(args: string[]): Promise<void> {
|
||||
|
||||
try {
|
||||
const client = new AzureDevOpsClient(ORGANIZATION, PROJECT);
|
||||
const data = await client.queueBuild(parsedArgs.definitionId, branch, parsedArgs.variables);
|
||||
const data = await client.queueBuild(parsedArgs.definitionId, branch, parsedArgs.parameters);
|
||||
|
||||
const buildId = data.id;
|
||||
const buildNumber = data.buildNumber;
|
||||
@@ -904,10 +912,10 @@ async function runQueueCommand(args: string[]): Promise<void> {
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('');
|
||||
console.log('To check status, run:');
|
||||
console.log(` node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId}`);
|
||||
console.log(` node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId}`);
|
||||
console.log('');
|
||||
console.log('To watch progress:');
|
||||
console.log(` node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId} --watch`);
|
||||
console.log(` node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId} --watch`);
|
||||
} catch (e) {
|
||||
const error = e instanceof Error ? e : new Error(String(e));
|
||||
console.error(colors.red('Error queuing build:'));
|
||||
@@ -921,7 +929,7 @@ async function runQueueCommand(args: string[]): Promise<void> {
|
||||
// ============================================================================
|
||||
|
||||
function printStatusUsage(): void {
|
||||
const scriptName = 'node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status';
|
||||
const scriptName = 'node .github/skills/azure-pipelines/azure-pipeline.ts status';
|
||||
console.log(`Usage: ${scriptName} [options]`);
|
||||
console.log('');
|
||||
console.log('Get status and logs of an Azure DevOps pipeline build.');
|
||||
@@ -1068,7 +1076,7 @@ async function runStatusCommand(args: string[]): Promise<void> {
|
||||
|
||||
if (!buildId) {
|
||||
console.error(colors.red(`Error: No builds found for branch '${branch}'.`));
|
||||
console.log('You can queue a new build with: node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts queue');
|
||||
console.log('You can queue a new build with: node .github/skills/azure-pipelines/azure-pipeline.ts queue');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -1162,7 +1170,7 @@ async function runStatusCommand(args: string[]): Promise<void> {
|
||||
// ============================================================================
|
||||
|
||||
function printCancelUsage(): void {
|
||||
const scriptName = 'node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts cancel';
|
||||
const scriptName = 'node .github/skills/azure-pipelines/azure-pipeline.ts cancel';
|
||||
console.log(`Usage: ${scriptName} --build-id <id> [options]`);
|
||||
console.log('');
|
||||
console.log('Cancel a running Azure DevOps pipeline build.');
|
||||
@@ -1233,7 +1241,7 @@ async function runCancelCommand(args: string[]): Promise<void> {
|
||||
console.error(colors.red('Error: --build-id is required.'));
|
||||
console.log('');
|
||||
console.log('To find build IDs, run:');
|
||||
console.log(' node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status');
|
||||
console.log(' node .github/skills/azure-pipelines/azure-pipeline.ts status');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1287,7 +1295,7 @@ async function runCancelCommand(args: string[]): Promise<void> {
|
||||
console.log('');
|
||||
console.log('The build will transition to "cancelling" state and then "canceled".');
|
||||
console.log('Check status with:');
|
||||
console.log(` node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId}`);
|
||||
console.log(` node .github/skills/azure-pipelines/azure-pipeline.ts status --build-id ${buildId}`);
|
||||
} catch (e) {
|
||||
const error = e instanceof Error ? e : new Error(String(e));
|
||||
console.error('');
|
||||
@@ -1390,15 +1398,15 @@ async function runAllTests(): Promise<void> {
|
||||
validateBranch('');
|
||||
});
|
||||
|
||||
it('validateVariables accepts valid variable formats', () => {
|
||||
validateVariables('KEY=value');
|
||||
validateVariables('MY_VAR=some-value');
|
||||
validateVariables('A=1 B=2 C=3');
|
||||
validateVariables('PATH=/usr/bin:path');
|
||||
it('validateParameters accepts valid parameter formats', () => {
|
||||
validateParameters(['KEY=value']);
|
||||
validateParameters(['MY_VAR=some-value']);
|
||||
validateParameters(['A=1', 'B=2', 'C=3']);
|
||||
validateParameters(['PATH=/usr/bin:path']);
|
||||
});
|
||||
|
||||
it('validateVariables accepts empty string', () => {
|
||||
validateVariables('');
|
||||
it('validateParameters accepts empty list', () => {
|
||||
validateParameters([]);
|
||||
});
|
||||
|
||||
it('validateArtifactName accepts valid artifact names', () => {
|
||||
@@ -1429,9 +1437,14 @@ async function runAllTests(): Promise<void> {
|
||||
assert.strictEqual(args.definitionId, '222');
|
||||
});
|
||||
|
||||
it('parseQueueArgs parses --variables correctly', () => {
|
||||
const args = parseQueueArgs(['--variables', 'KEY=value']);
|
||||
assert.strictEqual(args.variables, 'KEY=value');
|
||||
it('parseQueueArgs parses --parameters correctly', () => {
|
||||
const args = parseQueueArgs(['--parameters', 'KEY=value']);
|
||||
assert.deepStrictEqual(args.parameters, ['KEY=value']);
|
||||
});
|
||||
|
||||
it('parseQueueArgs parses repeated --parameter correctly', () => {
|
||||
const args = parseQueueArgs(['--parameter', 'A=1', '--parameter', 'B=two words']);
|
||||
assert.deepStrictEqual(args.parameters, ['A=1', 'B=two words']);
|
||||
});
|
||||
|
||||
it('parseQueueArgs parses --dry-run correctly', () => {
|
||||
@@ -1440,10 +1453,10 @@ async function runAllTests(): Promise<void> {
|
||||
});
|
||||
|
||||
it('parseQueueArgs parses combined arguments', () => {
|
||||
const args = parseQueueArgs(['--branch', 'main', '--definition', '333', '--variables', 'A=1 B=2', '--dry-run']);
|
||||
const args = parseQueueArgs(['--branch', 'main', '--definition', '333', '--parameters', 'A=1 B=2', '--dry-run']);
|
||||
assert.strictEqual(args.branch, 'main');
|
||||
assert.strictEqual(args.definitionId, '333');
|
||||
assert.strictEqual(args.variables, 'A=1 B=2');
|
||||
assert.deepStrictEqual(args.parameters, ['A=1', 'B=2']);
|
||||
assert.strictEqual(args.dryRun, true);
|
||||
});
|
||||
|
||||
@@ -1516,12 +1529,12 @@ async function runAllTests(): Promise<void> {
|
||||
assert.ok(cmd.includes('json'));
|
||||
});
|
||||
|
||||
it('queueBuild includes variables when provided', async () => {
|
||||
it('queueBuild includes parameters when provided', async () => {
|
||||
const client = new TestableAzureDevOpsClient(ORGANIZATION, PROJECT);
|
||||
await client.queueBuild('111', 'main', 'KEY=value OTHER=test');
|
||||
await client.queueBuild('111', 'main', ['KEY=value', 'OTHER=test']);
|
||||
|
||||
const cmd = client.capturedCommands[0];
|
||||
assert.ok(cmd.includes('--variables'));
|
||||
assert.ok(cmd.includes('--parameters'));
|
||||
assert.ok(cmd.includes('KEY=value'));
|
||||
assert.ok(cmd.includes('OTHER=test'));
|
||||
});
|
||||
@@ -1718,7 +1731,7 @@ async function runAllTests(): Promise<void> {
|
||||
describe('Integration Tests', () => {
|
||||
it('full queue command flow constructs correct az commands', async () => {
|
||||
const client = new TestableAzureDevOpsClient(ORGANIZATION, PROJECT);
|
||||
await client.queueBuild('111', 'feature/test', 'DEBUG=true');
|
||||
await client.queueBuild('111', 'feature/test', ['DEBUG=true']);
|
||||
|
||||
assert.strictEqual(client.capturedCommands.length, 1);
|
||||
const cmd = client.capturedCommands[0];
|
||||
@@ -1733,7 +1746,7 @@ async function runAllTests(): Promise<void> {
|
||||
assert.ok(cmd.includes('111'));
|
||||
assert.ok(cmd.includes('--branch'));
|
||||
assert.ok(cmd.includes('feature/test'));
|
||||
assert.ok(cmd.includes('--variables'));
|
||||
assert.ok(cmd.includes('--parameters'));
|
||||
assert.ok(cmd.includes('DEBUG=true'));
|
||||
});
|
||||
|
||||
@@ -1797,7 +1810,7 @@ async function runAllTests(): Promise<void> {
|
||||
// ============================================================================
|
||||
|
||||
function printMainUsage(): void {
|
||||
const scriptName = 'node --experimental-strip-types .github/skills/azure-pipelines/azure-pipeline.ts';
|
||||
const scriptName = 'node .github/skills/azure-pipelines/azure-pipeline.ts';
|
||||
console.log(`Usage: ${scriptName} <command> [options]`);
|
||||
console.log('');
|
||||
console.log('Azure DevOps Pipeline CLI for VS Code builds.');
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
---
|
||||
name: component-fixtures
|
||||
description: Use when creating or updating component fixtures for screenshot testing, or when designing UI components to be fixture-friendly. Covers fixture file structure, theming, service setup, CSS scoping, async rendering, and common pitfalls.
|
||||
---
|
||||
|
||||
# Component Fixtures
|
||||
|
||||
Component fixtures render isolated UI components for visual screenshot testing via the component explorer. Fixtures live in `src/vs/workbench/test/browser/componentFixtures/` and are auto-discovered by the Vite dev server using the glob `src/**/*.fixture.ts`.
|
||||
|
||||
Use tools `mcp_component-exp_`* to list and screenshot fixtures. If you cannot see these tools, inform the user to them on.
|
||||
|
||||
## Running Fixtures Locally
|
||||
|
||||
1. Start the component explorer daemon: run the **Launch Component Explorer** task
|
||||
2. Use the `mcp_component-exp_list_fixtures` tool to see all available fixtures and their URLs
|
||||
3. Use the `mcp_component-exp_screenshot` tool to capture screenshots programmatically
|
||||
|
||||
## File Structure
|
||||
|
||||
Each fixture file exports a default `defineThemedFixtureGroup(...)`. The file must end with `.fixture.ts`.
|
||||
|
||||
```
|
||||
src/vs/workbench/test/browser/componentFixtures/
|
||||
fixtureUtils.ts # Shared helpers (DO NOT import @vscode/component-explorer elsewhere)
|
||||
myComponent.fixture.ts # Your fixture file
|
||||
```
|
||||
|
||||
## Basic Pattern
|
||||
|
||||
```typescript
|
||||
import { ComponentFixtureContext, createEditorServices, defineComponentFixture, defineThemedFixtureGroup } from './fixtureUtils.js';
|
||||
|
||||
export default defineThemedFixtureGroup({ path: 'myFeature/' }, {
|
||||
Default: defineComponentFixture({ render: renderMyComponent }),
|
||||
AnotherVariant: defineComponentFixture({ render: renderMyComponent }),
|
||||
});
|
||||
|
||||
function renderMyComponent({ container, disposableStore, theme }: ComponentFixtureContext): void {
|
||||
container.style.width = '400px';
|
||||
|
||||
const instantiationService = createEditorServices(disposableStore, {
|
||||
colorTheme: theme,
|
||||
additionalServices: (reg) => {
|
||||
// Register additional services the component needs
|
||||
reg.define(IMyService, MyServiceImpl);
|
||||
reg.defineInstance(IMockService, mockInstance);
|
||||
},
|
||||
});
|
||||
|
||||
const widget = disposableStore.add(
|
||||
instantiationService.createInstance(MyWidget, /* constructor args */)
|
||||
);
|
||||
container.appendChild(widget.domNode);
|
||||
}
|
||||
```
|
||||
|
||||
Key points:
|
||||
- **`defineThemedFixtureGroup`** automatically creates Dark and Light variants for each fixture
|
||||
- **`defineComponentFixture`** wraps your render function with theme setup and shadow DOM isolation
|
||||
- **`createEditorServices`** provides a `TestInstantiationService` with base editor services pre-registered
|
||||
- Always register created widgets with `disposableStore.add(...)` to prevent leaks
|
||||
- Pass `colorTheme: theme` to `createEditorServices` so theme colors render correctly
|
||||
|
||||
## Utilities from fixtureUtils.ts
|
||||
|
||||
| Export | Purpose |
|
||||
|---|---|
|
||||
| `defineComponentFixture` | Creates Dark/Light themed fixture variants from a render function |
|
||||
| `defineThemedFixtureGroup` | Groups multiple themed fixtures into a named fixture group |
|
||||
| `createEditorServices` | Creates `TestInstantiationService` with all base editor services |
|
||||
| `registerWorkbenchServices` | Registers additional workbench services (context menu, label, etc.) |
|
||||
| `createTextModel` | Creates a text model via `ModelService` for editor fixtures |
|
||||
| `setupTheme` | Applies theme CSS to a container (called automatically by `defineComponentFixture`) |
|
||||
| `darkTheme` / `lightTheme` | Pre-loaded `ColorThemeData` instances |
|
||||
|
||||
**Important:** Only `fixtureUtils.ts` may import from `@vscode/component-explorer`. All fixture files must go through the helpers in `fixtureUtils.ts`.
|
||||
|
||||
## CSS Scoping
|
||||
|
||||
Fixtures render inside shadow DOM. The component-explorer automatically adopts the global VS Code stylesheets and theme CSS.
|
||||
|
||||
### Matching production CSS selectors
|
||||
|
||||
Many VS Code components have CSS rules scoped to deep ancestor selectors (e.g., `.interactive-session .interactive-input-part > .widget-container .my-element`). In fixtures, you must recreate the required ancestor DOM structure for these selectors to match:
|
||||
|
||||
```typescript
|
||||
function render({ container }: ComponentFixtureContext): void {
|
||||
container.classList.add('interactive-session');
|
||||
|
||||
// Recreate ancestor structure that CSS selectors expect
|
||||
const inputPart = dom.$('.interactive-input-part');
|
||||
const widgetContainer = dom.$('.widget-container');
|
||||
inputPart.appendChild(widgetContainer);
|
||||
container.appendChild(inputPart);
|
||||
|
||||
widgetContainer.appendChild(myWidget.domNode);
|
||||
}
|
||||
```
|
||||
|
||||
**Design recommendation for new components:** Avoid deeply nested CSS selectors that require specific ancestor elements. Use self-contained class names (e.g., `.my-widget .my-element` rather than `.parent-view .parent-part > .wrapper .my-element`). This makes components easier to fixture and reuse.
|
||||
|
||||
## Services
|
||||
|
||||
### Using createEditorServices
|
||||
|
||||
`createEditorServices` pre-registers these services: `IAccessibilityService`, `IKeybindingService`, `IClipboardService`, `IOpenerService`, `INotificationService`, `IDialogService`, `IUndoRedoService`, `ILanguageService`, `IConfigurationService`, `IStorageService`, `IThemeService`, `IModelService`, `ICodeEditorService`, `IContextKeyService`, `ICommandService`, `ITelemetryService`, `IHoverService`, `IUserInteractionService`, and more.
|
||||
|
||||
### Additional services
|
||||
|
||||
Register extra services via `additionalServices`:
|
||||
|
||||
```typescript
|
||||
createEditorServices(disposableStore, {
|
||||
additionalServices: (reg) => {
|
||||
// Class-based (instantiated by DI):
|
||||
reg.define(IMyService, MyServiceImpl);
|
||||
// Instance-based (pre-constructed):
|
||||
reg.defineInstance(IMyService, myMockInstance);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Mocking services
|
||||
|
||||
Use the `mock<T>()` helper from `base/test/common/mock.js` to create mock service instances:
|
||||
|
||||
```typescript
|
||||
import { mock } from '../../../../base/test/common/mock.js';
|
||||
|
||||
const myService = new class extends mock<IMyService>() {
|
||||
override someMethod(): string { return 'test'; }
|
||||
override onSomeEvent = Event.None;
|
||||
};
|
||||
reg.defineInstance(IMyService, myService);
|
||||
```
|
||||
|
||||
For mock view models or data objects:
|
||||
```typescript
|
||||
const element = new class extends mock<IChatRequestViewModel>() { }();
|
||||
```
|
||||
|
||||
## Async Rendering
|
||||
|
||||
The component explorer waits **2 animation frames** after the synchronous render function returns. For most components, this is sufficient.
|
||||
|
||||
If your render function returns a `Promise`, the component explorer waits for the promise to resolve.
|
||||
|
||||
### Pitfall: DOM reparenting causes flickering
|
||||
|
||||
Avoid moving rendered widgets between DOM parents after initial render. This causes:
|
||||
- Layout recalculation (the widget jumps as `position: absolute` coordinates become invalid)
|
||||
- Focus loss (blur events can trigger hide logic in widgets like QuickInput)
|
||||
- Screenshot instability (the component explorer may capture an intermediate layout state)
|
||||
|
||||
**Bad pattern — reparenting a widget after async wait:**
|
||||
```typescript
|
||||
async function render({ container }: ComponentFixtureContext): Promise<void> {
|
||||
const host = document.createElement('div');
|
||||
container.appendChild(host);
|
||||
// ... create widget inside host ...
|
||||
await waitForWidget();
|
||||
container.appendChild(widget); // BAD: reparenting causes flicker
|
||||
host.remove();
|
||||
}
|
||||
```
|
||||
|
||||
**Better pattern — render in-place with the correct DOM structure from the start:**
|
||||
```typescript
|
||||
function render({ container }: ComponentFixtureContext): void {
|
||||
// Set up the correct DOM structure first, then create the widget inside it
|
||||
const widget = createWidget(container);
|
||||
container.appendChild(widget.domNode);
|
||||
}
|
||||
```
|
||||
|
||||
If the component absolutely requires async setup (e.g., QuickInput which renders internally), minimize DOM manipulation after the widget appears by structuring the host container to match the final layout from the beginning.
|
||||
|
||||
## Adapting Existing Components for Fixtures
|
||||
|
||||
Existing components often need small changes to become fixturable. When writing a fixture reveals friction, fix the component — don't work around it in the fixture. Common adaptations:
|
||||
|
||||
### Decouple CSS from ancestor context
|
||||
|
||||
If a component's CSS only works inside a deeply nested selector like `.workbench .sidebar .my-view .my-widget`, refactor the CSS to be self-contained. Move the styles so they're scoped to the component's own root class:
|
||||
|
||||
```css
|
||||
/* Before: requires specific ancestors */
|
||||
.workbench .sidebar .my-view .my-widget .header { font-weight: bold; }
|
||||
|
||||
/* After: self-contained */
|
||||
.my-widget .header { font-weight: bold; }
|
||||
```
|
||||
|
||||
If the component shares styles with its parent (e.g., inheriting background color), use CSS custom properties rather than relying on ancestor selectors.
|
||||
|
||||
### Extract hard-coded service dependencies
|
||||
|
||||
If a component reaches into singletons or global state instead of using DI, refactor it to accept services through the constructor:
|
||||
|
||||
```typescript
|
||||
// Before: hard to mock in fixtures
|
||||
class MyWidget {
|
||||
private readonly config = getSomeGlobalConfig();
|
||||
}
|
||||
|
||||
// After: injectable and testable
|
||||
class MyWidget {
|
||||
constructor(@IConfigurationService private readonly configService: IConfigurationService) { }
|
||||
}
|
||||
```
|
||||
|
||||
### Add options to control auto-focus and animation
|
||||
|
||||
Components that auto-focus on creation or run animations cause flaky screenshots. Add an options parameter:
|
||||
|
||||
```typescript
|
||||
interface IMyWidgetOptions {
|
||||
shouldAutoFocus?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
The fixture passes `shouldAutoFocus: false`. The production call site keeps the default behavior.
|
||||
|
||||
### Expose internal state for "already completed" rendering
|
||||
|
||||
Many components have lifecycle states (loading → active → completed). If the component can only reach the "completed" state through user interaction, add support for initializing directly into that state via constructor data:
|
||||
|
||||
```typescript
|
||||
// The fixture can pass pre-filled data to render the summary/completed state
|
||||
// without simulating the full user interaction flow.
|
||||
const carousel: IChatQuestionCarousel = {
|
||||
questions,
|
||||
allowSkip: true,
|
||||
kind: 'questionCarousel',
|
||||
isUsed: true, // Already completed
|
||||
data: { 'q1': 'answer' }, // Pre-filled answers
|
||||
};
|
||||
```
|
||||
|
||||
### Make DOM node accessible
|
||||
|
||||
If a component builds its DOM internally and doesn't expose the root element, add a public `readonly domNode: HTMLElement` property so fixtures can append it to the container.
|
||||
|
||||
## Writing Fixture-Friendly Components
|
||||
|
||||
When designing new UI components, follow these practices to make them easy to fixture:
|
||||
|
||||
### 1. Accept a container element in the constructor
|
||||
|
||||
```typescript
|
||||
// Good: container is passed in
|
||||
class MyWidget {
|
||||
constructor(container: HTMLElement, @IFoo foo: IFoo) {
|
||||
this.domNode = dom.append(container, dom.$('.my-widget'));
|
||||
}
|
||||
}
|
||||
|
||||
// Also good: widget creates its own domNode for the caller to place
|
||||
class MyWidget {
|
||||
readonly domNode: HTMLElement;
|
||||
constructor(@IFoo foo: IFoo) {
|
||||
this.domNode = dom.$('.my-widget');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Use dependency injection for all services
|
||||
|
||||
All external dependencies should come through DI so fixtures can provide test implementations:
|
||||
|
||||
```typescript
|
||||
// Good: services injected
|
||||
constructor(@IThemeService private readonly themeService: IThemeService) { }
|
||||
|
||||
// Bad: reaching into globals
|
||||
constructor() { this.theme = getGlobalTheme(); }
|
||||
```
|
||||
|
||||
### 3. Keep CSS selectors shallow
|
||||
|
||||
```css
|
||||
/* Good: self-contained, easy to fixture */
|
||||
.my-widget .my-header { ... }
|
||||
.my-widget .my-list-item { ... }
|
||||
|
||||
/* Bad: requires deep ancestor chain */
|
||||
.workbench .sidebar .my-view .my-widget .my-header { ... }
|
||||
```
|
||||
|
||||
### 4. Avoid reading from layout/window services during construction
|
||||
|
||||
Components that measure the window or read layout dimensions during construction are hard to fixture because the shadow DOM container has different dimensions than the workbench:
|
||||
|
||||
```typescript
|
||||
// Prefer: use CSS for sizing, or accept dimensions as parameters
|
||||
container.style.width = '400px';
|
||||
container.style.height = '300px';
|
||||
|
||||
// Avoid: reading from layoutService during construction
|
||||
const width = this.layoutService.mainContainerDimension.width;
|
||||
```
|
||||
|
||||
### 5. Support disabling auto-focus in fixtures
|
||||
|
||||
Auto-focus can interfere with screenshot stability. Provide options to disable it:
|
||||
|
||||
```typescript
|
||||
interface IMyWidgetOptions {
|
||||
shouldAutoFocus?: boolean; // Fixtures pass false
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Expose the DOM node
|
||||
|
||||
The fixture needs to append the widget's DOM to the container. Expose it as a public `readonly domNode: HTMLElement`.
|
||||
|
||||
## Multiple Fixture Variants
|
||||
|
||||
Create variants to show different states of the same component:
|
||||
|
||||
```typescript
|
||||
export default defineThemedFixtureGroup({
|
||||
// Different data states
|
||||
Empty: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { items: [] }) }),
|
||||
WithItems: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { items: sampleItems }) }),
|
||||
|
||||
// Different configurations
|
||||
ReadOnly: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { readonly: true }) }),
|
||||
Editable: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { readonly: false }) }),
|
||||
|
||||
// Lifecycle states
|
||||
Loading: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { state: 'loading' }) }),
|
||||
Completed: defineComponentFixture({ render: (ctx) => renderWidget(ctx, { state: 'done' }) }),
|
||||
});
|
||||
```
|
||||
|
||||
## Learnings
|
||||
|
||||
Update this section with insights from your fixture development experience!
|
||||
|
||||
* Do not copy the component to the fixture and modify it there. Always adapt the original component to be fixture-friendly, then render it in the fixture. This ensures the fixture tests the real component code and lifecycle, rather than a modified version that may hide bugs.
|
||||
|
||||
* **Don't recompose child widgets in fixtures.** Never manually instantiate and add a sub-widget (e.g., a toolbar content widget) that the parent component is supposed to create. Instead, configure the parent correctly (e.g., set the right editor option, register the right provider) so the child appears through the normal code path. Manually recomposing hides integration bugs and doesn't test the real widget lifecycle.
|
||||
@@ -15,8 +15,6 @@ The `src/vs/sessions/` directory contains authoritative specification documents.
|
||||
| Layout spec | `src/vs/sessions/LAYOUT.md` | Grid structure, part positions, sizing, CSS classes, API reference |
|
||||
| AI Customizations | `src/vs/sessions/AI_CUSTOMIZATIONS.md` | AI customization editor and tree view design |
|
||||
| Chat Widget | `src/vs/sessions/browser/widget/AGENTS_CHAT_WIDGET.md` | Chat widget wrapper architecture, deferred session creation, option delivery |
|
||||
| AI Customization Mgmt | `src/vs/sessions/contrib/aiCustomizationManagement/browser/SPEC.md` | Management editor specification |
|
||||
| AI Customization Tree | `src/vs/sessions/contrib/aiCustomizationTreeView/browser/SPEC.md` | Tree view specification |
|
||||
|
||||
If you modify the implementation, you **must** update the corresponding spec to keep it in sync. Update the Revision History table at the bottom of `LAYOUT.md` with a dated entry.
|
||||
|
||||
@@ -62,44 +60,57 @@ src/vs/sessions/
|
||||
├── AI_CUSTOMIZATIONS.md # AI customization design document
|
||||
├── sessions.common.main.ts # Common (browser + desktop) entry point
|
||||
├── sessions.desktop.main.ts # Desktop entry point (imports all contributions)
|
||||
├── common/ # Shared types and context keys
|
||||
│ └── contextkeys.ts # ChatBar context keys
|
||||
├── common/ # Shared types, context keys, and theme
|
||||
│ ├── categories.ts # Command categories
|
||||
│ ├── contextkeys.ts # ChatBar and welcome context keys
|
||||
│ └── theme.ts # Theme contributions
|
||||
├── browser/ # Core workbench implementation
|
||||
│ ├── workbench.ts # Main Workbench class (implements IWorkbenchLayoutService)
|
||||
│ ├── menus.ts # Agent sessions menu IDs (Menus export)
|
||||
│ ├── layoutActions.ts # Layout toggle actions (sidebar, panel, auxiliary bar)
|
||||
│ ├── paneCompositePartService.ts # AgenticPaneCompositePartService
|
||||
│ ├── style.css # Layout-specific styles
|
||||
│ ├── widget/ # Agent sessions chat widget
|
||||
│ │ ├── AGENTS_CHAT_WIDGET.md # Chat widget architecture doc
|
||||
│ │ ├── agentSessionsChatWidget.ts # Main wrapper around ChatWidget
|
||||
│ │ ├── agentSessionsChatTargetConfig.ts # Observable target state
|
||||
│ │ ├── agentSessionsTargetPickerActionItem.ts # Target picker for input toolbar
|
||||
│ │ └── media/
|
||||
│ └── parts/ # Workbench part implementations
|
||||
│ ├── parts.ts # AgenticParts enum
|
||||
│ ├── titlebarPart.ts # Titlebar (3-section toolbar layout)
|
||||
│ ├── sidebarPart.ts # Sidebar (with footer for account widget)
|
||||
│ ├── chatBarPart.ts # Chat Bar (primary chat surface)
|
||||
│ ├── auxiliaryBarPart.ts # Auxiliary Bar (with run script dropdown)
|
||||
│ ├── panelPart.ts # Panel (terminal, output, etc.)
|
||||
│ ├── projectBarPart.ts # Project bar (folder entries)
|
||||
│ ├── agentSessionsChatInputPart.ts # Chat input part adapter
|
||||
│ ├── agentSessionsChatWelcomePart.ts # Welcome view (mascot + target buttons + pickers)
|
||||
│ └── media/ # Part CSS files
|
||||
│ │ └── AGENTS_CHAT_WIDGET.md # Chat widget architecture doc
|
||||
│ ├── parts/ # Workbench part implementations
|
||||
│ │ ├── parts.ts # AgenticParts enum
|
||||
│ │ ├── titlebarPart.ts # Titlebar (3-section toolbar layout)
|
||||
│ │ ├── sidebarPart.ts # Sidebar (with footer for account widget)
|
||||
│ │ ├── chatBarPart.ts # Chat Bar (primary chat surface)
|
||||
│ │ ├── auxiliaryBarPart.ts # Auxiliary Bar
|
||||
│ │ ├── panelPart.ts # Panel (terminal, output, etc.)
|
||||
│ │ ├── projectBarPart.ts # Project bar (folder entries)
|
||||
│ │ └── media/ # Part CSS files
|
||||
│ └── media/ # Layout-specific styles
|
||||
├── electron-browser/ # Desktop-specific entry points
|
||||
│ ├── sessions.main.ts # Desktop main bootstrap
|
||||
│ ├── sessions.ts # Electron process entry
|
||||
│ ├── sessions.html # Production HTML shell
|
||||
│ └── sessions-dev.html # Development HTML shell
|
||||
│ ├── sessions-dev.html # Development HTML shell
|
||||
│ ├── titleService.ts # Desktop title service override
|
||||
│ └── parts/
|
||||
│ └── titlebarPart.ts # Desktop titlebar part
|
||||
├── services/ # Service overrides
|
||||
│ ├── configuration/browser/ # Configuration service overrides
|
||||
│ └── workspace/browser/ # Workspace service overrides
|
||||
├── test/ # Unit tests
|
||||
│ └── browser/
|
||||
│ └── layoutActions.test.ts
|
||||
└── contrib/ # Feature contributions
|
||||
├── accountMenu/browser/ # Account widget for sidebar footer
|
||||
├── aiCustomizationManagement/browser/ # AI customization management editor
|
||||
├── agentFeedback/browser/ # Agent feedback attachments, overlays, hover
|
||||
├── aiCustomizationTreeView/browser/ # AI customization tree view sidebar
|
||||
├── applyToParentRepo/browser/ # Apply changes to parent repo
|
||||
├── changesView/browser/ # File changes view
|
||||
├── chat/browser/ # Chat actions (run script, branch, prompts)
|
||||
├── configuration/browser/ # Configuration overrides
|
||||
└── sessions/browser/ # Sessions view, title bar widget, active session service
|
||||
├── files/browser/ # File-related contributions
|
||||
├── fileTreeView/browser/ # File tree view (filesystem provider)
|
||||
├── gitSync/browser/ # Git sync contributions
|
||||
├── logs/browser/ # Log contributions
|
||||
├── sessions/browser/ # Sessions view, title bar widget, active session service
|
||||
├── terminal/browser/ # Terminal contributions
|
||||
├── welcome/browser/ # Welcome view contribution
|
||||
└── workspace/browser/ # Workspace contributions
|
||||
```
|
||||
|
||||
## 4. Layout
|
||||
@@ -165,18 +176,21 @@ The agent sessions window uses **its own menu IDs** defined in `browser/menus.ts
|
||||
|
||||
| Menu ID | Purpose |
|
||||
|---------|---------|
|
||||
| `Menus.TitleBarLeft` | Left toolbar (toggle sidebar) |
|
||||
| `Menus.TitleBarCenter` | Not used directly (see CommandCenter) |
|
||||
| `Menus.TitleBarRight` | Right toolbar (run script, open, toggle auxiliary bar) |
|
||||
| `Menus.ChatBarTitle` | Chat bar title actions |
|
||||
| `Menus.CommandCenter` | Center toolbar with session picker widget |
|
||||
| `Menus.TitleBarControlMenu` | Submenu intercepted to render `SessionsTitleBarWidget` |
|
||||
| `Menus.CommandCenterCenter` | Center section of command center |
|
||||
| `Menus.TitleBarContext` | Titlebar context menu |
|
||||
| `Menus.TitleBarLeftLayout` | Left layout toolbar |
|
||||
| `Menus.TitleBarSessionTitle` | Session title in titlebar |
|
||||
| `Menus.TitleBarSessionMenu` | Session menu in titlebar |
|
||||
| `Menus.TitleBarRightLayout` | Right layout toolbar |
|
||||
| `Menus.PanelTitle` | Panel title bar actions |
|
||||
| `Menus.SidebarTitle` | Sidebar title bar actions |
|
||||
| `Menus.SidebarFooter` | Sidebar footer (account widget) |
|
||||
| `Menus.SidebarCustomizations` | Sidebar customizations menu |
|
||||
| `Menus.AuxiliaryBarTitle` | Auxiliary bar title actions |
|
||||
| `Menus.AuxiliaryBarTitleLeft` | Auxiliary bar left title actions |
|
||||
| `Menus.OpenSubMenu` | "Open..." split button (Open Terminal, Open in VS Code) |
|
||||
| `Menus.ChatBarTitle` | Chat bar title actions |
|
||||
| `Menus.AgentFeedbackEditorContent` | Agent feedback editor content menu |
|
||||
|
||||
## 7. Context Keys
|
||||
|
||||
@@ -187,7 +201,7 @@ Defined in `common/contextkeys.ts`:
|
||||
| `activeChatBar` | `string` | ID of the active chat bar panel |
|
||||
| `chatBarFocus` | `boolean` | Whether chat bar has keyboard focus |
|
||||
| `chatBarVisible` | `boolean` | Whether chat bar is visible |
|
||||
|
||||
| `sessionsWelcomeVisible` | `boolean` | Whether the sessions welcome overlay is visible |
|
||||
## 8. Contributions
|
||||
|
||||
Feature contributions live under `contrib/<featureName>/browser/` and are registered via imports in `sessions.desktop.main.ts` (desktop) or `sessions.common.main.ts` (browser-compatible).
|
||||
@@ -199,13 +213,18 @@ Feature contributions live under `contrib/<featureName>/browser/` and are regist
|
||||
| **Sessions View** | `contrib/sessions/browser/` | Sessions list in sidebar, session picker, active session service |
|
||||
| **Title Bar Widget** | `contrib/sessions/browser/sessionsTitleBarWidget.ts` | Session picker in titlebar center |
|
||||
| **Account Widget** | `contrib/accountMenu/browser/` | Account button in sidebar footer |
|
||||
| **Run Script** | `contrib/chat/browser/runScriptAction.ts` | Run configured script in terminal |
|
||||
| **Branch Chat Session** | `contrib/chat/browser/branchChatSessionAction.ts` | Branch a chat session |
|
||||
| **Open in VS Code / Terminal** | `contrib/chat/browser/chat.contribution.ts` | Open worktree in VS Code or terminal |
|
||||
| **Prompts Service** | `contrib/chat/browser/promptsService.ts` | Agentic prompts service override |
|
||||
| **Chat Actions** | `contrib/chat/browser/` | Chat actions (run script, branch, prompts, customizations debug log) |
|
||||
| **Changes View** | `contrib/changesView/browser/` | File changes in auxiliary bar |
|
||||
| **AI Customization Editor** | `contrib/aiCustomizationManagement/browser/` | Management editor for prompts, hooks, MCP, etc. |
|
||||
| **Agent Feedback** | `contrib/agentFeedback/browser/` | Agent feedback attachments, editor overlays, hover |
|
||||
| **AI Customization Tree** | `contrib/aiCustomizationTreeView/browser/` | Sidebar tree for AI customizations |
|
||||
| **Apply to Parent Repo** | `contrib/applyToParentRepo/browser/` | Apply changes to parent repo |
|
||||
| **Files** | `contrib/files/browser/` | File-related contributions |
|
||||
| **File Tree View** | `contrib/fileTreeView/browser/` | File tree view (filesystem provider) |
|
||||
| **Git Sync** | `contrib/gitSync/browser/` | Git sync contributions |
|
||||
| **Logs** | `contrib/logs/browser/` | Log contributions |
|
||||
| **Terminal** | `contrib/terminal/browser/` | Terminal contributions |
|
||||
| **Welcome** | `contrib/welcome/browser/` | Welcome view contribution |
|
||||
| **Workspace** | `contrib/workspace/browser/` | Workspace contributions |
|
||||
| **Configuration** | `contrib/configuration/browser/` | Configuration overrides |
|
||||
|
||||
### 8.2 Service Overrides
|
||||
@@ -216,6 +235,10 @@ The agent sessions window registers its own implementations for:
|
||||
- `IPromptsService` → `AgenticPromptsService` (scopes prompt discovery to active session worktree)
|
||||
- `IActiveSessionService` → `ActiveSessionService` (tracks active session)
|
||||
|
||||
Service overrides also live under `services/`:
|
||||
- `services/configuration/browser/` - configuration service overrides
|
||||
- `services/workspace/browser/` - workspace service overrides
|
||||
|
||||
### 8.3 `WindowVisibility.Sessions`
|
||||
|
||||
Views and contributions that should only appear in the agent sessions window (not in regular VS Code) use `WindowVisibility.Sessions` in their registration.
|
||||
@@ -224,12 +247,14 @@ Views and contributions that should only appear in the agent sessions window (no
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `sessions.common.main.ts` | Common entry — imports browser-compatible services, workbench contributions |
|
||||
| `sessions.desktop.main.ts` | Desktop entry — imports desktop services, electron contributions, all `contrib/` modules |
|
||||
| `sessions.common.main.ts` | Common entry; imports browser-compatible services, workbench contributions |
|
||||
| `sessions.desktop.main.ts` | Desktop entry; imports desktop services, electron contributions, all `contrib/` modules |
|
||||
| `electron-browser/sessions.main.ts` | Desktop bootstrap |
|
||||
| `electron-browser/sessions.ts` | Electron process entry |
|
||||
| `electron-browser/sessions.html` | Production HTML shell |
|
||||
| `electron-browser/sessions-dev.html` | Development HTML shell |
|
||||
| `electron-browser/titleService.ts` | Desktop title service override |
|
||||
| `electron-browser/parts/titlebarPart.ts` | Desktop titlebar part |
|
||||
|
||||
## 10. Development Guidelines
|
||||
|
||||
@@ -243,7 +268,13 @@ Views and contributions that should only appear in the agent sessions window (no
|
||||
6. Use agent session part classes, not standard workbench parts
|
||||
7. Mark views with `WindowVisibility.Sessions` so they only appear in this window
|
||||
|
||||
### 10.2 Layout Changes
|
||||
### 10.2 Validating Changes
|
||||
|
||||
1. Run `npm run compile-check-ts-native` to run a repo-wide TypeScript compilation check (including `src/vs/sessions/`). This is a fast way to catch TypeScript errors introduced by your changes.
|
||||
2. Run `npm run valid-layers-check` to verify layering rules are not violated.
|
||||
3. Run tests under `src/vs/sessions/test/` to confirm nothing is broken.
|
||||
|
||||
### 10.3 Layout Changes
|
||||
|
||||
1. **Read `LAYOUT.md` first** — it's the authoritative spec
|
||||
2. Use the `agent-sessions-layout` skill for detailed implementation guidance
|
||||
|
||||
@@ -212,7 +212,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
- name: Publish Crash Reports
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -223,7 +223,7 @@ jobs:
|
||||
# In order to properly symbolify above crash reports
|
||||
# (if any), we need the compiled native modules too
|
||||
- name: Publish Node Modules
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Publish Log Files
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
|
||||
@@ -258,7 +258,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
- name: Publish Crash Reports
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
# In order to properly symbolify above crash reports
|
||||
# (if any), we need the compiled native modules too
|
||||
- name: Publish Node Modules
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -278,7 +278,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Publish Log Files
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
|
||||
@@ -249,7 +249,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
- name: Publish Crash Reports
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -260,7 +260,7 @@ jobs:
|
||||
# In order to properly symbolify above crash reports
|
||||
# (if any), we need the compiled native modules too
|
||||
- name: Publish Node Modules
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
continue-on-error: true
|
||||
with:
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Publish Log Files
|
||||
uses: actions/upload-artifact@v6
|
||||
uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
with:
|
||||
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
working-directory: build
|
||||
|
||||
- name: Compile & Hygiene
|
||||
run: npm exec -- npm-run-all2 -lp core-ci extensions-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
|
||||
run: npm exec -- npm-run-all2 -lp core-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Screenshot Tests
|
||||
name: Checking Component Screenshots
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -10,8 +10,6 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
checks: write
|
||||
statuses: write
|
||||
|
||||
concurrency:
|
||||
@@ -20,15 +18,16 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
screenshots:
|
||||
name: Checking Component Screenshots
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
|
||||
@@ -74,14 +73,14 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload explorer artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: component-explorer
|
||||
path: /tmp/explorer-artifact/
|
||||
|
||||
- name: Upload screenshot report
|
||||
if: steps.compare.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: screenshot-diff
|
||||
path: |
|
||||
@@ -95,39 +94,19 @@ jobs:
|
||||
REPORT="test/componentFixtures/.screenshots/report/report.json"
|
||||
if [ -f "$REPORT" ]; then
|
||||
CHANGED=$(node -e "const r = require('./$REPORT'); console.log(r.summary.added + r.summary.removed + r.summary.changed)")
|
||||
TITLE="${CHANGED} screenshots changed"
|
||||
TITLE="⚠ ${CHANGED} screenshots changed"
|
||||
else
|
||||
TITLE="Screenshots match"
|
||||
TITLE="✅ Screenshots match"
|
||||
fi
|
||||
|
||||
SHA="${{ github.event.pull_request.head.sha || github.sha }}"
|
||||
CHECK_RUN_ID=$(gh api "repos/${{ github.repository }}/commits/$SHA/check-runs" \
|
||||
--jq '.check_runs[] | select(.name == "screenshots") | .id')
|
||||
|
||||
DETAILS_URL="https://hediet-ghartifactpreview.azurewebsites.net/${{ github.repository }}/run/${{ github.run_id }}/component-explorer/___explorer.html?report=./screenshot-report/report.json"
|
||||
|
||||
if [ -n "$CHECK_RUN_ID" ]; then
|
||||
gh api "repos/${{ github.repository }}/check-runs/$CHECK_RUN_ID" \
|
||||
-X PATCH --input - <<EOF || echo "::warning::Could not update check run (expected for fork PRs)"
|
||||
{"details_url":"$DETAILS_URL","output":{"title":"$TITLE","summary":"$TITLE"}}
|
||||
EOF
|
||||
fi
|
||||
|
||||
DETAILS_URL="https://hediet-ghartifactpreview.azurewebsites.net/${{ github.repository }}/run/${{ github.run_id }}/component-explorer/___explorer.html?report=./screenshot-report/report.json"
|
||||
gh api "repos/${{ github.repository }}/statuses/$SHA" \
|
||||
--input - <<EOF || echo "::warning::Could not create commit status (expected for fork PRs)"
|
||||
{"state":"success","target_url":"$DETAILS_URL","description":"$TITLE","context":"screenshots / explorer"}
|
||||
{"state":"success","target_url":"$DETAILS_URL","description":"$TITLE","context":"Component Screenshots"}
|
||||
EOF
|
||||
|
||||
- name: Post summary
|
||||
run: |
|
||||
if [ -f test/componentFixtures/.screenshots/report/report.md ]; then
|
||||
cat test/componentFixtures/.screenshots/report/report.md >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "## Screenshots ✅" >> $GITHUB_STEP_SUMMARY
|
||||
echo "No visual changes detected." >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
# - name: Post PR comment
|
||||
# if: github.event_name == 'pull_request'
|
||||
# env:
|
||||
|
||||
Vendored
+5
-1
@@ -4,11 +4,15 @@
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"editorconfig.editorconfig",
|
||||
"github.vscode-pull-request-github",
|
||||
"ms-vscode.vscode-github-issue-notebooks",
|
||||
"ms-vscode.extension-test-runner",
|
||||
"jrieken.vscode-pr-pinger",
|
||||
"typescriptteam.native-preview",
|
||||
"ms-vscode.ts-customized-language-service"
|
||||
],
|
||||
"stronglyRecommended": [
|
||||
"github.vscode-pull-request-github",
|
||||
"ms-vscode.vscode-extras",
|
||||
"ms-vscode.vscode-selfhost-test-provider"
|
||||
]
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "vscode-extras",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vscode-extras",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"vscode": "^1.88.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "vscode-extras",
|
||||
"displayName": "VS Code Extras",
|
||||
"description": "Extra utility features for the VS Code selfhost workspace",
|
||||
"engines": {
|
||||
"vscode": "^1.88.0"
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"publisher": "ms-vscode",
|
||||
"categories": [
|
||||
"Other"
|
||||
],
|
||||
"activationEvents": [
|
||||
"workspaceContains:src/vscode-dts/vscode.d.ts"
|
||||
],
|
||||
"main": "./out/extension.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/vscode.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"compile": "gulp compile-extension:vscode-extras",
|
||||
"watch": "gulp watch-extension:vscode-extras"
|
||||
},
|
||||
"contributes": {
|
||||
"configuration": {
|
||||
"title": "VS Code Extras",
|
||||
"properties": {
|
||||
"vscode-extras.npmUpToDateFeature.enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Show a status bar warning when npm dependencies are out of date."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { NpmUpToDateFeature } from './npmUpToDateFeature';
|
||||
|
||||
export class Extension extends vscode.Disposable {
|
||||
private readonly _output: vscode.LogOutputChannel;
|
||||
private _npmFeature: NpmUpToDateFeature | undefined;
|
||||
|
||||
constructor(_context: vscode.ExtensionContext) {
|
||||
const disposables: vscode.Disposable[] = [];
|
||||
super(() => disposables.forEach(d => d.dispose()));
|
||||
|
||||
this._output = vscode.window.createOutputChannel('VS Code Extras', { log: true });
|
||||
disposables.push(this._output);
|
||||
|
||||
this._updateNpmFeature();
|
||||
|
||||
disposables.push(
|
||||
vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('vscode-extras.npmUpToDateFeature.enabled')) {
|
||||
this._updateNpmFeature();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _updateNpmFeature(): void {
|
||||
const enabled = vscode.workspace.getConfiguration('vscode-extras').get<boolean>('npmUpToDateFeature.enabled', true);
|
||||
if (enabled && !this._npmFeature) {
|
||||
this._npmFeature = new NpmUpToDateFeature(this._output);
|
||||
} else if (!enabled && this._npmFeature) {
|
||||
this._npmFeature.dispose();
|
||||
this._npmFeature = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let extension: Extension | undefined;
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
extension = new Extension(context);
|
||||
context.subscriptions.push(extension);
|
||||
}
|
||||
|
||||
export function deactivate() {
|
||||
extension = undefined;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
interface FileHashes {
|
||||
readonly [relativePath: string]: string;
|
||||
}
|
||||
|
||||
interface PostinstallState {
|
||||
readonly nodeVersion: string;
|
||||
readonly fileHashes: FileHashes;
|
||||
}
|
||||
|
||||
interface InstallState {
|
||||
readonly root: string;
|
||||
readonly stateContentsFile: string;
|
||||
readonly current: PostinstallState;
|
||||
readonly saved: PostinstallState | undefined;
|
||||
readonly files: readonly string[];
|
||||
}
|
||||
|
||||
export class NpmUpToDateFeature extends vscode.Disposable {
|
||||
private readonly _statusBarItem: vscode.StatusBarItem;
|
||||
private readonly _disposables: vscode.Disposable[] = [];
|
||||
private _watchers: fs.FSWatcher[] = [];
|
||||
private _terminal: vscode.Terminal | undefined;
|
||||
private _stateContentsFile: string | undefined;
|
||||
private _root: string | undefined;
|
||||
|
||||
private static readonly _scheme = 'npm-dep-state';
|
||||
|
||||
constructor(private readonly _output: vscode.LogOutputChannel) {
|
||||
const disposables: vscode.Disposable[] = [];
|
||||
super(() => {
|
||||
disposables.forEach(d => d.dispose());
|
||||
for (const w of this._watchers) {
|
||||
w.close();
|
||||
}
|
||||
});
|
||||
this._disposables = disposables;
|
||||
|
||||
this._statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 10000);
|
||||
this._statusBarItem.name = 'npm Install State';
|
||||
this._statusBarItem.text = '$(warning) node_modules is stale - run npm i';
|
||||
this._statusBarItem.tooltip = 'Dependencies are out of date. Click to run npm install.';
|
||||
this._statusBarItem.command = 'vscode-extras.runNpmInstall';
|
||||
this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
|
||||
this._disposables.push(this._statusBarItem);
|
||||
|
||||
this._disposables.push(
|
||||
vscode.workspace.registerTextDocumentContentProvider(NpmUpToDateFeature._scheme, {
|
||||
provideTextDocumentContent: (uri) => {
|
||||
const params = new URLSearchParams(uri.query);
|
||||
const source = params.get('source');
|
||||
const file = uri.path.slice(1); // strip leading /
|
||||
if (source === 'saved') {
|
||||
return this._readSavedContent(file);
|
||||
}
|
||||
return this._readCurrentContent(file);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._disposables.push(
|
||||
vscode.commands.registerCommand('vscode-extras.runNpmInstall', () => this._runNpmInstall())
|
||||
);
|
||||
|
||||
this._disposables.push(
|
||||
vscode.commands.registerCommand('vscode-extras.showDependencyDiff', (file: string) => this._showDiff(file))
|
||||
);
|
||||
|
||||
this._disposables.push(
|
||||
vscode.window.onDidCloseTerminal(t => {
|
||||
if (t === this._terminal) {
|
||||
this._terminal = undefined;
|
||||
this._check();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this._check();
|
||||
}
|
||||
|
||||
private _runNpmInstall(): void {
|
||||
if (this._terminal) {
|
||||
this._terminal.dispose();
|
||||
}
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri;
|
||||
if (!workspaceRoot) {
|
||||
return;
|
||||
}
|
||||
this._terminal = vscode.window.createTerminal({ name: 'npm install', cwd: workspaceRoot });
|
||||
this._terminal.sendText('node build/npm/fast-install.ts --force');
|
||||
this._terminal.show();
|
||||
|
||||
this._statusBarItem.text = '$(loading~spin) npm i';
|
||||
this._statusBarItem.tooltip = 'npm install is running...';
|
||||
this._statusBarItem.backgroundColor = undefined;
|
||||
this._statusBarItem.command = 'vscode-extras.runNpmInstall';
|
||||
}
|
||||
|
||||
private _queryState(): InstallState | undefined {
|
||||
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
|
||||
if (!workspaceRoot) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
const script = path.join(workspaceRoot, 'build', 'npm', 'installStateHash.ts');
|
||||
const output = cp.execFileSync(process.execPath, [script], {
|
||||
cwd: workspaceRoot,
|
||||
timeout: 10_000,
|
||||
encoding: 'utf8',
|
||||
});
|
||||
const parsed = JSON.parse(output.trim());
|
||||
this._output.trace('raw output:', output.trim());
|
||||
return parsed;
|
||||
} catch (e) {
|
||||
this._output.error('_queryState error:', e as any);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private _check(): void {
|
||||
const state = this._queryState();
|
||||
this._output.trace('state:', JSON.stringify(state, null, 2));
|
||||
if (!state) {
|
||||
this._output.trace('no state, hiding');
|
||||
this._statusBarItem.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
this._stateContentsFile = state.stateContentsFile;
|
||||
this._root = state.root;
|
||||
this._setupWatcher(state);
|
||||
|
||||
const changedFiles = this._getChangedFiles(state);
|
||||
this._output.trace('changedFiles:', JSON.stringify(changedFiles));
|
||||
|
||||
if (changedFiles.length === 0) {
|
||||
this._statusBarItem.hide();
|
||||
} else {
|
||||
this._statusBarItem.text = '$(warning) node_modules is stale - run npm i';
|
||||
const tooltip = new vscode.MarkdownString();
|
||||
tooltip.isTrusted = true;
|
||||
tooltip.supportHtml = true;
|
||||
tooltip.appendMarkdown('**Dependencies are out of date.** Click to run npm install.\n\nChanged files:\n\n');
|
||||
for (const entry of changedFiles) {
|
||||
if (entry.isFile) {
|
||||
const args = encodeURIComponent(JSON.stringify(entry.label));
|
||||
tooltip.appendMarkdown(`- [${entry.label}](command:vscode-extras.showDependencyDiff?${args})\n`);
|
||||
} else {
|
||||
tooltip.appendMarkdown(`- ${entry.label}\n`);
|
||||
}
|
||||
}
|
||||
this._statusBarItem.tooltip = tooltip;
|
||||
this._statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
|
||||
this._statusBarItem.show();
|
||||
}
|
||||
}
|
||||
|
||||
private _showDiff(file: string): void {
|
||||
const cacheBuster = Date.now().toString();
|
||||
const savedUri = vscode.Uri.from({
|
||||
scheme: NpmUpToDateFeature._scheme,
|
||||
path: `/${file}`,
|
||||
query: new URLSearchParams({ source: 'saved', t: cacheBuster }).toString(),
|
||||
});
|
||||
const currentUri = vscode.Uri.from({
|
||||
scheme: NpmUpToDateFeature._scheme,
|
||||
path: `/${file}`,
|
||||
query: new URLSearchParams({ source: 'current', t: cacheBuster }).toString(),
|
||||
});
|
||||
|
||||
vscode.commands.executeCommand('vscode.diff', savedUri, currentUri, `${file} (last install ↔ current)`);
|
||||
}
|
||||
|
||||
private _readSavedContent(file: string): string {
|
||||
if (!this._stateContentsFile) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
const contents: Record<string, string> = JSON.parse(fs.readFileSync(this._stateContentsFile, 'utf8'));
|
||||
return contents[file] ?? '';
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private _readCurrentContent(file: string): string {
|
||||
if (!this._root) {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
return this._normalizeFileContent(path.join(this._root, file));
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
private _normalizeFileContent(filePath: string): string {
|
||||
const raw = fs.readFileSync(filePath, 'utf8');
|
||||
if (path.basename(filePath) === 'package.json') {
|
||||
const json = JSON.parse(raw);
|
||||
for (const key of NpmUpToDateFeature._packageJsonIgnoredKeys) {
|
||||
delete json[key];
|
||||
}
|
||||
return JSON.stringify(json, null, '\t') + '\n';
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
private static readonly _packageJsonIgnoredKeys = ['distro'];
|
||||
|
||||
private _getChangedFiles(state: InstallState): { readonly label: string; readonly isFile: boolean }[] {
|
||||
if (!state.saved) {
|
||||
return [{ label: '(no postinstall state found)', isFile: false }];
|
||||
}
|
||||
const changed: { readonly label: string; readonly isFile: boolean }[] = [];
|
||||
if (state.saved.nodeVersion !== state.current.nodeVersion) {
|
||||
changed.push({ label: `Node.js version (${state.saved.nodeVersion} → ${state.current.nodeVersion})`, isFile: false });
|
||||
}
|
||||
const allKeys = new Set([...Object.keys(state.current.fileHashes), ...Object.keys(state.saved.fileHashes)]);
|
||||
for (const key of allKeys) {
|
||||
if (state.current.fileHashes[key] !== state.saved.fileHashes[key]) {
|
||||
changed.push({ label: key, isFile: true });
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
private _setupWatcher(state: InstallState): void {
|
||||
for (const w of this._watchers) {
|
||||
w.close();
|
||||
}
|
||||
this._watchers = [];
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
const scheduleCheck = () => {
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer);
|
||||
}
|
||||
debounceTimer = setTimeout(() => this._check(), 500);
|
||||
};
|
||||
|
||||
for (const file of state.files) {
|
||||
try {
|
||||
const watcher = fs.watch(file, scheduleCheck);
|
||||
this._watchers.push(watcher);
|
||||
} catch {
|
||||
// file may not exist yet
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../../extensions/tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./out",
|
||||
"types": [
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"../../../src/vscode-dts/vscode.d.ts"
|
||||
]
|
||||
}
|
||||
Vendored
+72
-2
@@ -278,6 +278,51 @@
|
||||
"hidden": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch VS Sessions Internal",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/code.bat"
|
||||
},
|
||||
"osx": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/code.sh"
|
||||
},
|
||||
"linux": {
|
||||
"runtimeExecutable": "${workspaceFolder}/scripts/code.sh"
|
||||
},
|
||||
"port": 9222,
|
||||
"timeout": 0,
|
||||
"env": {
|
||||
"VSCODE_EXTHOST_WILL_SEND_SOCKET": null,
|
||||
"VSCODE_SKIP_PRELAUNCH": "1",
|
||||
"VSCODE_DEV_DEBUG_OBSERVABLES": "1",
|
||||
},
|
||||
"cleanUp": "wholeBrowser",
|
||||
"killBehavior": "polite",
|
||||
"runtimeArgs": [
|
||||
"--inspect-brk=5875",
|
||||
"--no-cached-data",
|
||||
"--crash-reporter-directory=${workspaceFolder}/.profile-oss/crashes",
|
||||
// for general runtime freezes: https://github.com/microsoft/vscode/issues/127861#issuecomment-904144910
|
||||
"--disable-features=CalculateNativeWinOcclusion",
|
||||
"--disable-extension=vscode.vscode-api-tests",
|
||||
"--sessions"
|
||||
],
|
||||
"userDataDir": "${userHome}/.vscode-oss-sessions-dev",
|
||||
"webRoot": "${workspaceFolder}",
|
||||
"cascadeTerminateToConfigurations": [
|
||||
"Attach to Extension Host"
|
||||
],
|
||||
"pauseForSourceMap": false,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/**/*.js"
|
||||
],
|
||||
"browserLaunchLocation": "workspace",
|
||||
"presentation": {
|
||||
"hidden": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// To debug observables you also need the extension "ms-vscode.debug-value-editor"
|
||||
"type": "chrome",
|
||||
@@ -603,9 +648,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Component Explorer",
|
||||
"name": "Component Explorer (Edge)",
|
||||
"type": "msedge",
|
||||
"port": 9230,
|
||||
"request": "launch",
|
||||
"url": "http://localhost:5337/___explorer",
|
||||
"preLaunchTask": "Launch Component Explorer",
|
||||
"presentation": {
|
||||
"group": "1_component_explorer",
|
||||
"order": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Component Explorer (Chrome)",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:5337/___explorer",
|
||||
"preLaunchTask": "Launch Component Explorer",
|
||||
@@ -653,6 +708,21 @@
|
||||
"order": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "VS Sessions",
|
||||
"stopAll": true,
|
||||
"configurations": [
|
||||
"Launch VS Sessions Internal",
|
||||
"Attach to Main Process",
|
||||
"Attach to Extension Host",
|
||||
"Attach to Shared Process",
|
||||
],
|
||||
"preLaunchTask": "Ensure Prelaunch Dependencies",
|
||||
"presentation": {
|
||||
"group": "0_vscode",
|
||||
"order": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "VS Code (Hot Reload)",
|
||||
"stopAll": true,
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce repo:microsoft/vscode-copilot-issues repo:microsoft/vscode-extension-samples\n\n// current milestone name\n$MILESTONE=milestone:\"February 2026\"\n"
|
||||
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce repo:microsoft/vscode-copilot-issues repo:microsoft/vscode-extension-samples\n\n// current milestone name\n$MILESTONE=milestone:\"March 2026\"\n"
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
|
||||
Vendored
+29
-4
@@ -225,8 +225,7 @@
|
||||
"windows": {
|
||||
"command": ".\\scripts\\code.bat"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"inSessions": true
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run Dev Sessions",
|
||||
@@ -238,6 +237,18 @@
|
||||
"args": [
|
||||
"--sessions"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run and Compile Dev Sessions",
|
||||
"type": "shell",
|
||||
"command": "npm run transpile-client && ./scripts/code.sh",
|
||||
"windows": {
|
||||
"command": "npm run transpile-client && .\\scripts\\code.bat"
|
||||
},
|
||||
"args": [
|
||||
"--sessions"
|
||||
],
|
||||
"inSessions": true,
|
||||
"problemMatcher": []
|
||||
},
|
||||
@@ -375,9 +386,23 @@
|
||||
{
|
||||
"label": "Launch Component Explorer",
|
||||
"type": "shell",
|
||||
"command": "npx component-explorer serve -c ./test/componentFixtures/component-explorer.json",
|
||||
"command": "npx component-explorer serve -c ./test/componentFixtures/component-explorer.json -vv",
|
||||
"isBackground": true,
|
||||
"problemMatcher": []
|
||||
"problemMatcher": {
|
||||
"owner": "component-explorer",
|
||||
"fileLocation": "absolute",
|
||||
"pattern": {
|
||||
"regexp": "^\\s*at\\s+(.+?):(\\d+):(\\d+)\\s*$",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3
|
||||
},
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": ".*Setting up sessions.*",
|
||||
"endsPattern": "Redirection server listening on.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -64,15 +64,6 @@ jobs:
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- script: tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
displayName: Extract compilation output
|
||||
|
||||
- script: node build/setup-npm-registry.ts $NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
@@ -173,6 +164,11 @@ jobs:
|
||||
|
||||
- template: ../common/install-builtin-extensions.yml@self
|
||||
|
||||
- script: npm run gulp core-ci
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
TARGET=$([ "$VSCODE_ARCH" == "x64" ] && echo "linux-alpine" || echo "alpine-arm64") # TODO@joaomoreno
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
cd $BUILD_STAGINGDIRECTORY
|
||||
mkdir extraction
|
||||
cd extraction
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-extension-telemetry.git
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-chrome-debug-core.git
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-node-debug2.git
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-node-debug.git
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-html-languageservice.git
|
||||
git clone --depth 1 https://github.com/microsoft/vscode-json-languageservice.git
|
||||
node $BUILD_SOURCESDIRECTORY/node_modules/.bin/vscode-telemetry-extractor --sourceDir $BUILD_SOURCESDIRECTORY --excludedDir $BUILD_SOURCESDIRECTORY/extensions --outputDir . --applyEndpoints
|
||||
node $BUILD_SOURCESDIRECTORY/node_modules/.bin/vscode-telemetry-extractor --config $BUILD_SOURCESDIRECTORY/build/azure-pipelines/common/telemetry-config.json -o .
|
||||
mkdir -p $BUILD_SOURCESDIRECTORY/.build/telemetry
|
||||
mv declarations-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-core.json
|
||||
mv config-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json
|
||||
cd ..
|
||||
rm -rf extraction
|
||||
@@ -0,0 +1,95 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import cp from 'child_process';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
const BUILD_STAGINGDIRECTORY = process.env.BUILD_STAGINGDIRECTORY ?? fs.mkdtempSync(path.join(os.tmpdir(), 'vscode-telemetry-'));
|
||||
const BUILD_SOURCESDIRECTORY = process.env.BUILD_SOURCESDIRECTORY ?? path.resolve(import.meta.dirname, '..', '..', '..');
|
||||
|
||||
const extractionDir = path.join(BUILD_STAGINGDIRECTORY, 'extraction');
|
||||
fs.mkdirSync(extractionDir, { recursive: true });
|
||||
|
||||
const repos = [
|
||||
'https://github.com/microsoft/vscode-extension-telemetry.git',
|
||||
'https://github.com/microsoft/vscode-chrome-debug-core.git',
|
||||
'https://github.com/microsoft/vscode-node-debug2.git',
|
||||
'https://github.com/microsoft/vscode-node-debug.git',
|
||||
'https://github.com/microsoft/vscode-html-languageservice.git',
|
||||
'https://github.com/microsoft/vscode-json-languageservice.git',
|
||||
];
|
||||
|
||||
for (const repo of repos) {
|
||||
cp.execSync(`git clone --depth 1 ${repo}`, { cwd: extractionDir, stdio: 'inherit' });
|
||||
}
|
||||
|
||||
const extractor = path.join(BUILD_SOURCESDIRECTORY, 'node_modules', '@vscode', 'telemetry-extractor', 'out', 'extractor.js');
|
||||
const telemetryConfig = path.join(BUILD_SOURCESDIRECTORY, 'build', 'azure-pipelines', 'common', 'telemetry-config.json');
|
||||
|
||||
interface ITelemetryConfigEntry {
|
||||
eventPrefix: string;
|
||||
sourceDirs: string[];
|
||||
excludedDirs: string[];
|
||||
applyEndpoints: boolean;
|
||||
patchDebugEvents?: boolean;
|
||||
}
|
||||
|
||||
const pipelineExtensionsPathPrefix = '../../s/extensions/';
|
||||
|
||||
const telemetryConfigEntries = JSON.parse(fs.readFileSync(telemetryConfig, 'utf8')) as ITelemetryConfigEntry[];
|
||||
let hasLocalConfigOverrides = false;
|
||||
|
||||
const resolvedTelemetryConfigEntries = telemetryConfigEntries.map(entry => {
|
||||
const sourceDirs = entry.sourceDirs.map(sourceDir => {
|
||||
if (!sourceDir.startsWith(pipelineExtensionsPathPrefix)) {
|
||||
return sourceDir;
|
||||
}
|
||||
|
||||
const sourceDirInExtractionDir = path.resolve(extractionDir, sourceDir);
|
||||
if (fs.existsSync(sourceDirInExtractionDir)) {
|
||||
return sourceDir;
|
||||
}
|
||||
|
||||
const extensionRelativePath = sourceDir.slice(pipelineExtensionsPathPrefix.length);
|
||||
const sourceDirInWorkspace = path.join(BUILD_SOURCESDIRECTORY, 'extensions', extensionRelativePath);
|
||||
if (fs.existsSync(sourceDirInWorkspace)) {
|
||||
hasLocalConfigOverrides = true;
|
||||
return sourceDirInWorkspace;
|
||||
}
|
||||
|
||||
return sourceDir;
|
||||
});
|
||||
|
||||
return {
|
||||
...entry,
|
||||
sourceDirs,
|
||||
};
|
||||
});
|
||||
|
||||
const telemetryConfigForExtraction = hasLocalConfigOverrides
|
||||
? path.join(extractionDir, 'telemetry-config.local.json')
|
||||
: telemetryConfig;
|
||||
|
||||
if (hasLocalConfigOverrides) {
|
||||
fs.writeFileSync(telemetryConfigForExtraction, JSON.stringify(resolvedTelemetryConfigEntries, null, '\t'));
|
||||
}
|
||||
|
||||
try {
|
||||
cp.execSync(`node "${extractor}" --sourceDir "${BUILD_SOURCESDIRECTORY}" --excludedDir "${path.join(BUILD_SOURCESDIRECTORY, 'extensions')}" --outputDir . --applyEndpoints`, { cwd: extractionDir, stdio: 'inherit' });
|
||||
cp.execSync(`node "${extractor}" --config "${telemetryConfigForExtraction}" -o .`, { cwd: extractionDir, stdio: 'inherit' });
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
console.error(`Telemetry extraction failed: ${message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const telemetryDir = path.join(BUILD_SOURCESDIRECTORY, '.build', 'telemetry');
|
||||
fs.mkdirSync(telemetryDir, { recursive: true });
|
||||
fs.renameSync(path.join(extractionDir, 'declarations-resolved.json'), path.join(telemetryDir, 'telemetry-core.json'));
|
||||
fs.renameSync(path.join(extractionDir, 'config-resolved.json'), path.join(telemetryDir, 'telemetry-extensions.json'));
|
||||
|
||||
fs.rmSync(extractionDir, { recursive: true, force: true });
|
||||
@@ -970,15 +970,7 @@ async function main() {
|
||||
console.log(`\u2705 ${name}`);
|
||||
}
|
||||
|
||||
const stages = new Set<string>(['Compile']);
|
||||
|
||||
if (
|
||||
e('VSCODE_BUILD_STAGE_LINUX') === 'True' ||
|
||||
e('VSCODE_BUILD_STAGE_MACOS') === 'True' ||
|
||||
e('VSCODE_BUILD_STAGE_WINDOWS') === 'True'
|
||||
) {
|
||||
stages.add('CompileCLI');
|
||||
}
|
||||
const stages = new Set<string>(['Quality']);
|
||||
|
||||
if (e('VSCODE_BUILD_STAGE_WINDOWS') === 'True') { stages.add('Windows'); }
|
||||
if (e('VSCODE_BUILD_STAGE_LINUX') === 'True') { stages.add('Linux'); }
|
||||
|
||||
@@ -29,18 +29,36 @@ jobs:
|
||||
name: ${{ parameters.poolName }}
|
||||
os: ${{ parameters.os }}
|
||||
timeoutInMinutes: 30
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(SCREENSHOTS_DIR)
|
||||
artifactName: screenshots-${{ parameters.name }}
|
||||
displayName: Publish Screenshots
|
||||
condition: succeededOrFailed()
|
||||
continueOnError: true
|
||||
sbomEnabled: false
|
||||
variables:
|
||||
TEST_DIR: $(Build.SourcesDirectory)/test/sanity
|
||||
LOG_FILE: $(TEST_DIR)/results.xml
|
||||
SCREENSHOTS_DIR: $(TEST_DIR)/screenshots
|
||||
DOCKER_CACHE_DIR: $(Pipeline.Workspace)/docker-cache
|
||||
DOCKER_CACHE_FILE: $(DOCKER_CACHE_DIR)/${{ parameters.container }}.tar
|
||||
steps:
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
fetchTags: false
|
||||
sparseCheckoutDirectories: test/sanity .nvmrc
|
||||
sparseCheckoutDirectories: build/azure-pipelines/config test/sanity .nvmrc
|
||||
displayName: Checkout test/sanity
|
||||
|
||||
- ${{ if eq(parameters.os, 'windows') }}:
|
||||
- script: mkdir "$(SCREENSHOTS_DIR)"
|
||||
displayName: Create Screenshots Directory
|
||||
|
||||
- ${{ else }}:
|
||||
- bash: mkdir -p "$(SCREENSHOTS_DIR)"
|
||||
displayName: Create Screenshots Directory
|
||||
|
||||
- ${{ if and(eq(parameters.os, 'windows'), eq(parameters.arch, 'arm64')) }}:
|
||||
- script: |
|
||||
@echo off
|
||||
@@ -101,19 +119,19 @@ jobs:
|
||||
|
||||
# Windows
|
||||
- ${{ if eq(parameters.os, 'windows') }}:
|
||||
- script: $(TEST_DIR)/scripts/run-win32.cmd -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -v ${{ parameters.args }}
|
||||
- script: $(TEST_DIR)/scripts/run-win32.cmd -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -s $(SCREENSHOTS_DIR) -v ${{ parameters.args }}
|
||||
workingDirectory: $(TEST_DIR)
|
||||
displayName: Run Sanity Tests
|
||||
|
||||
# macOS
|
||||
- ${{ if eq(parameters.os, 'macOS') }}:
|
||||
- bash: $(TEST_DIR)/scripts/run-macOS.sh -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -v ${{ parameters.args }}
|
||||
- bash: $(TEST_DIR)/scripts/run-macOS.sh -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -s $(SCREENSHOTS_DIR) -v ${{ parameters.args }}
|
||||
workingDirectory: $(TEST_DIR)
|
||||
displayName: Run Sanity Tests
|
||||
|
||||
# Native Linux host
|
||||
- ${{ if and(eq(parameters.container, ''), eq(parameters.os, 'linux')) }}:
|
||||
- bash: $(TEST_DIR)/scripts/run-ubuntu.sh -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -v ${{ parameters.args }}
|
||||
- bash: $(TEST_DIR)/scripts/run-ubuntu.sh -c $(BUILD_COMMIT) -q $(BUILD_QUALITY) -t $(LOG_FILE) -s $(SCREENSHOTS_DIR) -v ${{ parameters.args }}
|
||||
workingDirectory: $(TEST_DIR)
|
||||
displayName: Run Sanity Tests
|
||||
|
||||
@@ -141,6 +159,7 @@ jobs:
|
||||
--quality "$(BUILD_QUALITY)" \
|
||||
--commit "$(BUILD_COMMIT)" \
|
||||
--test-results "/root/results.xml" \
|
||||
--screenshots-dir "/root/screenshots" \
|
||||
--verbose \
|
||||
${{ parameters.args }}
|
||||
workingDirectory: $(TEST_DIR)
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
parameters:
|
||||
- name: VSCODE_BUILD_MACOS
|
||||
type: boolean
|
||||
- name: VSCODE_BUILD_MACOS_ARM64
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
- job: macOSCLISign
|
||||
timeoutInMinutes: 90
|
||||
templateContext:
|
||||
outputParentDirectory: $(Build.ArtifactStagingDirectory)/out
|
||||
outputs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_darwin_x64_cli/vscode_cli_darwin_x64_cli.zip
|
||||
artifactName: vscode_cli_darwin_x64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_darwin_x64_cli
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/sign/unsigned_vscode_cli_darwin_x64_cli
|
||||
sbomPackageName: "VS Code macOS x64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_darwin_arm64_cli/vscode_cli_darwin_arm64_cli.zip
|
||||
artifactName: vscode_cli_darwin_arm64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_darwin_arm64_cli
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/sign/unsigned_vscode_cli_darwin_arm64_cli
|
||||
sbomPackageName: "VS Code macOS arm64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- script: node build/setup-npm-registry.ts $NPM_REGISTRY build
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
npm config set registry "$NPM_REGISTRY"
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$(npm config get userconfig)"
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Install build dependencies
|
||||
|
||||
- template: ./steps/product-build-darwin-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_CLI_ARTIFACTS:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}:
|
||||
- unsigned_vscode_cli_darwin_x64_cli
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS_ARM64, true) }}:
|
||||
- unsigned_vscode_cli_darwin_arm64_cli
|
||||
@@ -9,8 +9,8 @@ parameters:
|
||||
|
||||
jobs:
|
||||
- job: macOSCLI_${{ parameters.VSCODE_ARCH }}
|
||||
displayName: macOS (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
timeoutInMinutes: 60
|
||||
displayName: macOS CLI (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
timeoutInMinutes: 90
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
@@ -24,11 +24,12 @@ jobs:
|
||||
outputs:
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli artifact
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_darwin_$(VSCODE_ARCH)_cli/vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish vscode_cli_darwin_$(VSCODE_ARCH)_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/sign/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
sbomPackageName: "VS Code macOS $(VSCODE_ARCH) CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
@@ -83,3 +84,55 @@ jobs:
|
||||
VSCODE_CLI_ENV:
|
||||
OPENSSL_LIB_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-osx/lib
|
||||
OPENSSL_INCLUDE_DIR: $(Build.ArtifactStagingDirectory)/openssl/arm64-osx/include
|
||||
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish unsigned CLI
|
||||
sbomEnabled: false
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
mkdir -p $(Build.ArtifactStagingDirectory)/pkg/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
cp $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip $(Build.ArtifactStagingDirectory)/pkg/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
displayName: Prepare CLI for signing
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract unsigned CLI (for SBOM)
|
||||
inputs:
|
||||
archiveFilePatterns: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
destinationFolder: $(Build.ArtifactStagingDirectory)/sign/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- script: node build/azure-pipelines/common/sign.ts $(Agent.RootDirectory)/_tasks/EsrpCodeSigning_*/*/net6.0/esrpcli.dll sign-darwin $(Build.ArtifactStagingDirectory)/pkg/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli "*.zip"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- script: node build/azure-pipelines/common/sign.ts $(Agent.RootDirectory)/_tasks/EsrpCodeSigning_*/*/net6.0/esrpcli.dll notarize-darwin $(Build.ArtifactStagingDirectory)/pkg/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli "*.zip"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Notarize
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
mkdir -p $(Build.ArtifactStagingDirectory)/out/vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
mv $(Build.ArtifactStagingDirectory)/pkg/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli/unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip $(Build.ArtifactStagingDirectory)/out/vscode_cli_darwin_$(VSCODE_ARCH)_cli/vscode_cli_darwin_$(VSCODE_ARCH)_cli.zip
|
||||
displayName: Rename signed artifact
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
parameters:
|
||||
- name: VSCODE_CLI_ARTIFACTS
|
||||
type: object
|
||||
default: []
|
||||
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download ${{ target }}
|
||||
inputs:
|
||||
artifact: ${{ target }}
|
||||
path: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract artifact
|
||||
inputs:
|
||||
archiveFilePatterns: $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/*.zip
|
||||
destinationFolder: $(Build.ArtifactStagingDirectory)/sign/${{ target }}
|
||||
|
||||
- script: node build/azure-pipelines/common/sign.ts $(Agent.RootDirectory)/_tasks/EsrpCodeSigning_*/*/net6.0/esrpcli.dll sign-darwin $(Build.ArtifactStagingDirectory)/pkg "*.zip"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- script: node build/azure-pipelines/common/sign.ts $(Agent.RootDirectory)/_tasks/EsrpCodeSigning_*/*/net6.0/esrpcli.dll notarize-darwin $(Build.ArtifactStagingDirectory)/pkg "*.zip"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Notarize
|
||||
|
||||
- ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}:
|
||||
- script: |
|
||||
set -e
|
||||
ASSET_ID=$(echo "${{ target }}" | sed "s/unsigned_//")
|
||||
mkdir -p $(Build.ArtifactStagingDirectory)/out/$ASSET_ID
|
||||
mv $(Build.ArtifactStagingDirectory)/pkg/${{ target }}/${{ target }}.zip $(Build.ArtifactStagingDirectory)/out/$ASSET_ID/$ASSET_ID.zip
|
||||
echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID"
|
||||
displayName: Set asset id variable
|
||||
@@ -30,15 +30,6 @@ steps:
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password,macos-developer-certificate,macos-developer-certificate-key"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- script: tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
displayName: Extract compilation output
|
||||
|
||||
- script: node build/setup-npm-registry.ts $NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
@@ -112,11 +103,33 @@ steps:
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npx deemon --detach --wait -- node build/azure-pipelines/common/waitForArtifacts.ts unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact (background)
|
||||
|
||||
- script: node build/azure-pipelines/distro/mixin-quality.ts
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: ../../common/install-builtin-extensions.yml@self
|
||||
|
||||
- script: npm run gulp core-ci
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile
|
||||
|
||||
- script: node build/azure-pipelines/common/extract-telemetry.ts
|
||||
displayName: Generate lists of telemetry events
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile --prefix test/smoke
|
||||
npm run compile --prefix test/integration/browser
|
||||
displayName: Compile test suites (non-OSS)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npm run copy-policy-dto --prefix build && node build/lib/policies/policyGenerator.ts build/lib/policies/policyData.jsonc darwin
|
||||
displayName: Generate policy definitions
|
||||
@@ -147,6 +160,11 @@ steps:
|
||||
displayName: Build server (web)
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npx deemon --attach -- node build/azure-pipelines/common/waitForArtifacts.ts unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: unsigned_vscode_cli_darwin_$(VSCODE_ARCH)_cli
|
||||
|
||||
@@ -5,6 +5,9 @@ parameters:
|
||||
type: string
|
||||
- name: VSCODE_TEST_SUITE
|
||||
type: string
|
||||
- name: VSCODE_RUN_CHECKS
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
- job: Linux${{ parameters.VSCODE_TEST_SUITE }}
|
||||
@@ -43,6 +46,7 @@ jobs:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CIBUILD: ${{ parameters.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }}
|
||||
VSCODE_RUN_CHECKS: ${{ parameters.VSCODE_RUN_CHECKS }}
|
||||
${{ if eq(parameters.VSCODE_TEST_SUITE, 'Electron') }}:
|
||||
VSCODE_RUN_ELECTRON_TESTS: true
|
||||
${{ if eq(parameters.VSCODE_TEST_SUITE, 'Browser') }}:
|
||||
|
||||
@@ -9,7 +9,7 @@ parameters:
|
||||
|
||||
jobs:
|
||||
- job: LinuxCLI_${{ parameters.VSCODE_ARCH }}
|
||||
displayName: Linux (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
displayName: Linux CLI (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
timeoutInMinutes: 60
|
||||
pool:
|
||||
name: 1es-ubuntu-22.04-x64
|
||||
|
||||
@@ -19,6 +19,9 @@ parameters:
|
||||
- name: VSCODE_RUN_REMOTE_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_RUN_CHECKS
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
- job: Linux_${{ parameters.VSCODE_ARCH }}
|
||||
@@ -26,6 +29,7 @@ jobs:
|
||||
timeoutInMinutes: 90
|
||||
variables:
|
||||
DISPLAY: ":10"
|
||||
BUILDS_API_URL: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/
|
||||
NPM_ARCH: ${{ parameters.NPM_ARCH }}
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
templateContext:
|
||||
@@ -110,3 +114,4 @@ jobs:
|
||||
VSCODE_RUN_ELECTRON_TESTS: ${{ parameters.VSCODE_RUN_ELECTRON_TESTS }}
|
||||
VSCODE_RUN_BROWSER_TESTS: ${{ parameters.VSCODE_RUN_BROWSER_TESTS }}
|
||||
VSCODE_RUN_REMOTE_TESTS: ${{ parameters.VSCODE_RUN_REMOTE_TESTS }}
|
||||
VSCODE_RUN_CHECKS: ${{ parameters.VSCODE_RUN_CHECKS }}
|
||||
|
||||
@@ -17,6 +17,9 @@ parameters:
|
||||
- name: VSCODE_RUN_REMOTE_TESTS
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_RUN_CHECKS
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
steps:
|
||||
- template: ../../common/checkout.yml@self
|
||||
@@ -35,15 +38,6 @@ steps:
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- script: tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
displayName: Extract compilation output
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
# Start X server
|
||||
@@ -165,11 +159,34 @@ steps:
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npx deemon --detach --wait -- node build/azure-pipelines/common/waitForArtifacts.ts $(ARTIFACT_PREFIX)vscode_cli_linux_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact (background)
|
||||
|
||||
- script: node build/azure-pipelines/distro/mixin-quality.ts
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: ../../common/install-builtin-extensions.yml@self
|
||||
|
||||
- script: npm run gulp core-ci
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_ARCH, 'x64') }}:
|
||||
- script: node build/azure-pipelines/common/extract-telemetry.ts
|
||||
displayName: Generate lists of telemetry events
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile --prefix test/smoke
|
||||
npm run compile --prefix test/integration/browser
|
||||
displayName: Compile test suites (non-OSS)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npm run copy-policy-dto --prefix build && node build/lib/policies/policyGenerator.ts build/lib/policies/policyData.jsonc linux
|
||||
displayName: Generate policy definitions
|
||||
@@ -187,6 +204,11 @@ steps:
|
||||
displayName: Build client
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- script: npx deemon --attach -- node build/azure-pipelines/common/waitForArtifacts.ts $(ARTIFACT_PREFIX)vscode_cli_linux_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: $(ARTIFACT_PREFIX)vscode_cli_linux_$(VSCODE_ARCH)_cli
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
pr: none
|
||||
|
||||
trigger: none
|
||||
|
||||
parameters:
|
||||
- name: VSCODE_QUALITY
|
||||
displayName: Quality
|
||||
type: string
|
||||
default: insider
|
||||
- name: NPM_REGISTRY
|
||||
displayName: "Custom NPM Registry"
|
||||
type: string
|
||||
default: 'https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/npm/registry/'
|
||||
- name: CARGO_REGISTRY
|
||||
displayName: "Custom Cargo Registry"
|
||||
type: string
|
||||
default: 'sparse+https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/Cargo/index/'
|
||||
|
||||
variables:
|
||||
- name: NPM_REGISTRY
|
||||
${{ if in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }}: # disable terrapin when in VSCODE_CIBUILD
|
||||
value: none
|
||||
${{ else }}:
|
||||
value: ${{ parameters.NPM_REGISTRY }}
|
||||
- name: CARGO_REGISTRY
|
||||
value: ${{ parameters.CARGO_REGISTRY }}
|
||||
- name: VSCODE_QUALITY
|
||||
value: ${{ parameters.VSCODE_QUALITY }}
|
||||
- name: VSCODE_CIBUILD
|
||||
value: ${{ in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }}
|
||||
- name: VSCODE_STEP_ON_IT
|
||||
value: false
|
||||
- name: skipComponentGovernanceDetection
|
||||
value: true
|
||||
- name: ComponentDetection.Timeout
|
||||
value: 600
|
||||
- name: Codeql.SkipTaskAutoInjection
|
||||
value: true
|
||||
- name: ARTIFACT_PREFIX
|
||||
value: ''
|
||||
|
||||
name: "$(Date:yyyyMMdd).$(Rev:r) (${{ parameters.VSCODE_QUALITY }})"
|
||||
|
||||
resources:
|
||||
repositories:
|
||||
- repository: 1esPipelines
|
||||
type: git
|
||||
name: 1ESPipelineTemplates/1ESPipelineTemplates
|
||||
ref: refs/tags/release
|
||||
|
||||
extends:
|
||||
template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
|
||||
parameters:
|
||||
sdl:
|
||||
tsa:
|
||||
enabled: true
|
||||
configFile: $(Build.SourcesDirectory)/build/azure-pipelines/config/tsaoptions.json
|
||||
codeql:
|
||||
runSourceLanguagesInSourceAnalysis: true
|
||||
compiled:
|
||||
enabled: false
|
||||
justificationForDisabling: "CodeQL breaks ESRP CodeSign on macOS (ICM #520035761, githubcustomers/microsoft-codeql-support#198)"
|
||||
credscan:
|
||||
suppressionsFile: $(Build.SourcesDirectory)/build/azure-pipelines/config/CredScanSuppressions.json
|
||||
eslint:
|
||||
enabled: true
|
||||
enableExclusions: true
|
||||
exclusionsFilePath: $(Build.SourcesDirectory)/.eslint-ignore
|
||||
sourceAnalysisPool: 1es-windows-2022-x64
|
||||
createAdoIssuesForJustificationsForDisablement: false
|
||||
containers:
|
||||
ubuntu-2004-arm64:
|
||||
image: onebranch.azurecr.io/linux/ubuntu-2004-arm64:latest
|
||||
stages:
|
||||
- stage: Compile
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
demands:
|
||||
- ImageOverride -equals ACES_VM_SharedPool_Sequoia
|
||||
jobs:
|
||||
- template: build/azure-pipelines/product-compile.yml@self
|
||||
|
||||
- stage: macOS
|
||||
dependsOn:
|
||||
- Compile
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
demands:
|
||||
- ImageOverride -equals ACES_VM_SharedPool_Sequoia
|
||||
variables:
|
||||
BUILDSECMON_OPT_IN: true
|
||||
jobs:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: true
|
||||
VSCODE_TEST_SUITE: Electron
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: true
|
||||
VSCODE_TEST_SUITE: Browser
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-ci.yml@self
|
||||
parameters:
|
||||
VSCODE_CIBUILD: true
|
||||
VSCODE_TEST_SUITE: Remote
|
||||
@@ -26,6 +26,13 @@ parameters:
|
||||
- exploration
|
||||
- insider
|
||||
- stable
|
||||
- name: VSCODE_BUILD_TYPE
|
||||
displayName: Build Type
|
||||
type: string
|
||||
default: Product
|
||||
values:
|
||||
- Product
|
||||
- CI
|
||||
- name: NPM_REGISTRY
|
||||
displayName: "Custom NPM Registry"
|
||||
type: string
|
||||
@@ -90,10 +97,6 @@ parameters:
|
||||
displayName: "Release build if successful"
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_COMPILE_ONLY
|
||||
displayName: "Run Compile stage exclusively"
|
||||
type: boolean
|
||||
default: false
|
||||
- name: VSCODE_STEP_ON_IT
|
||||
displayName: "Skip tests"
|
||||
type: boolean
|
||||
@@ -119,9 +122,9 @@ variables:
|
||||
- name: VSCODE_BUILD_STAGE_WEB
|
||||
value: ${{ eq(parameters.VSCODE_BUILD_WEB, true) }}
|
||||
- name: VSCODE_CIBUILD
|
||||
value: ${{ in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI') }}
|
||||
value: ${{ or(in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI'), eq(parameters.VSCODE_BUILD_TYPE, 'CI')) }}
|
||||
- name: VSCODE_PUBLISH
|
||||
value: ${{ and(eq(parameters.VSCODE_PUBLISH, true), eq(variables.VSCODE_CIBUILD, false), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}
|
||||
value: ${{ and(eq(parameters.VSCODE_PUBLISH, true), eq(variables.VSCODE_CIBUILD, false)) }}
|
||||
- name: VSCODE_SCHEDULEDBUILD
|
||||
value: ${{ eq(variables['Build.Reason'], 'Schedule') }}
|
||||
- name: VSCODE_STEP_ON_IT
|
||||
@@ -190,27 +193,21 @@ extends:
|
||||
ubuntu-2004-arm64:
|
||||
image: onebranch.azurecr.io/linux/ubuntu-2004-arm64:latest
|
||||
stages:
|
||||
- stage: Compile
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
demands:
|
||||
- ImageOverride -equals ACES_VM_SharedPool_Sequoia
|
||||
jobs:
|
||||
- template: build/azure-pipelines/product-compile.yml@self
|
||||
|
||||
- ${{ if eq(variables['VSCODE_PUBLISH'], 'true') }}:
|
||||
- stage: ValidationChecks
|
||||
- stage: Quality
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: 1es-ubuntu-22.04-x64
|
||||
os: linux
|
||||
jobs:
|
||||
- template: build/azure-pipelines/product-quality-checks.yml@self
|
||||
|
||||
- ${{ if eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true) }}:
|
||||
- stage: Windows
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: 1es-ubuntu-22.04-x64
|
||||
os: linux
|
||||
jobs:
|
||||
- template: build/azure-pipelines/product-validation-checks.yml@self
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- stage: CompileCLI
|
||||
dependsOn: []
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
jobs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli.yml@self
|
||||
@@ -225,88 +222,6 @@ extends:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true)) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: armhf
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], true), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}:
|
||||
- stage: node_modules
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/linux/product-build-linux-node-modules.yml@self
|
||||
parameters:
|
||||
NPM_ARCH: arm64
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/linux/product-build-linux-node-modules.yml@self
|
||||
parameters:
|
||||
NPM_ARCH: arm
|
||||
VSCODE_ARCH: armhf
|
||||
- template: build/azure-pipelines/alpine/product-build-alpine-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
- template: build/azure-pipelines/alpine/product-build-alpine-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
- template: build/azure-pipelines/web/product-build-web-node-modules.yml@self
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}:
|
||||
- stage: APIScan
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
jobs:
|
||||
- job: WindowsAPIScan
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/sdl-scan-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WINDOWS'], true)) }}:
|
||||
- stage: Windows
|
||||
dependsOn:
|
||||
- Compile
|
||||
- ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- CompileCLI
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
jobs:
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-ci.yml@self
|
||||
parameters:
|
||||
@@ -341,22 +256,32 @@ extends:
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true))) }}:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_BUILD_WIN32: ${{ parameters.VSCODE_BUILD_WIN32 }}
|
||||
VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }}
|
||||
|
||||
- ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_LINUX'], true)) }}:
|
||||
- ${{ if eq(variables['VSCODE_BUILD_STAGE_LINUX'], true) }}:
|
||||
- stage: Linux
|
||||
dependsOn:
|
||||
- Compile
|
||||
- ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- CompileCLI
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: 1es-ubuntu-22.04-x64
|
||||
os: linux
|
||||
jobs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_LINUX, true) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARM64, true)) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true)) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: armhf
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
|
||||
- template: build/azure-pipelines/linux/product-build-linux-ci.yml@self
|
||||
parameters:
|
||||
@@ -402,10 +327,9 @@ extends:
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_ALPINE'], true)) }}:
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(variables['VSCODE_BUILD_STAGE_ALPINE'], true)) }}:
|
||||
- stage: Alpine
|
||||
dependsOn:
|
||||
- Compile
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_ALPINE, true) }}:
|
||||
- template: build/azure-pipelines/alpine/product-build-alpine.yml@self
|
||||
@@ -424,12 +348,9 @@ extends:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_MACOS'], true)) }}:
|
||||
- ${{ if eq(variables['VSCODE_BUILD_STAGE_MACOS'], true) }}:
|
||||
- stage: macOS
|
||||
dependsOn:
|
||||
- Compile
|
||||
- ${{ if or(eq(parameters.VSCODE_BUILD_LINUX, true),eq(parameters.VSCODE_BUILD_LINUX_ARMHF, true),eq(parameters.VSCODE_BUILD_LINUX_ARM64, true),eq(parameters.VSCODE_BUILD_MACOS, true),eq(parameters.VSCODE_BUILD_MACOS_ARM64, true),eq(parameters.VSCODE_BUILD_WIN32, true),eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }}:
|
||||
- CompileCLI
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: AcesShared
|
||||
os: macOS
|
||||
@@ -438,6 +359,19 @@ extends:
|
||||
variables:
|
||||
BUILDSECMON_OPT_IN: true
|
||||
jobs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_MACOS, true) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_CHECK_ONLY: ${{ variables.VSCODE_CIBUILD }}
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true)) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-cli.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-ci.yml@self
|
||||
parameters:
|
||||
@@ -470,20 +404,13 @@ extends:
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(variables['VSCODE_BUILD_MACOS_UNIVERSAL'], true)) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-universal.yml@self
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), or(eq(parameters.VSCODE_BUILD_MACOS, true), eq(parameters.VSCODE_BUILD_MACOS_ARM64, true))) }}:
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_BUILD_MACOS: ${{ parameters.VSCODE_BUILD_MACOS }}
|
||||
VSCODE_BUILD_MACOS_ARM64: ${{ parameters.VSCODE_BUILD_MACOS_ARM64 }}
|
||||
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_WEB'], true)) }}:
|
||||
- ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(variables['VSCODE_BUILD_STAGE_WEB'], true)) }}:
|
||||
- stage: Web
|
||||
dependsOn:
|
||||
- Compile
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: build/azure-pipelines/web/product-build-web.yml@self
|
||||
|
||||
- ${{ if eq(variables['VSCODE_PUBLISH'], 'true') }}:
|
||||
- ${{ if eq(variables['VSCODE_PUBLISH'], true) }}:
|
||||
- stage: Publish
|
||||
dependsOn: []
|
||||
jobs:
|
||||
@@ -811,3 +738,43 @@ extends:
|
||||
- template: build/azure-pipelines/product-release.yml@self
|
||||
parameters:
|
||||
VSCODE_RELEASE: ${{ parameters.VSCODE_RELEASE }}
|
||||
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], true) }}:
|
||||
- stage: node_modules
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: build/azure-pipelines/win32/product-build-win32-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/linux/product-build-linux-node-modules.yml@self
|
||||
parameters:
|
||||
NPM_ARCH: arm64
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/linux/product-build-linux-node-modules.yml@self
|
||||
parameters:
|
||||
NPM_ARCH: arm
|
||||
VSCODE_ARCH: armhf
|
||||
- template: build/azure-pipelines/alpine/product-build-alpine-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
- template: build/azure-pipelines/alpine/product-build-alpine-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: arm64
|
||||
- template: build/azure-pipelines/darwin/product-build-darwin-node-modules.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
- template: build/azure-pipelines/web/product-build-web-node-modules.yml@self
|
||||
|
||||
- ${{ if eq(variables['VSCODE_CIBUILD'], false) }}:
|
||||
- stage: APIScan
|
||||
dependsOn: []
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
jobs:
|
||||
- job: WindowsAPIScan
|
||||
steps:
|
||||
- template: build/azure-pipelines/win32/sdl-scan-win32.yml@self
|
||||
parameters:
|
||||
VSCODE_ARCH: x64
|
||||
VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }}
|
||||
|
||||
+67
-63
@@ -1,14 +1,12 @@
|
||||
jobs:
|
||||
- job: Compile
|
||||
timeoutInMinutes: 60
|
||||
templateContext:
|
||||
outputs:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
artifactName: Compilation
|
||||
displayName: Publish compilation artifact
|
||||
isProduction: false
|
||||
sbomEnabled: false
|
||||
- job: Quality
|
||||
displayName: Quality Checks
|
||||
timeoutInMinutes: 20
|
||||
variables:
|
||||
- name: skipComponentGovernanceDetection
|
||||
value: true
|
||||
- name: Codeql.SkipTaskAutoInjection
|
||||
value: true
|
||||
steps:
|
||||
- template: ./common/checkout.yml@self
|
||||
|
||||
@@ -30,7 +28,7 @@ jobs:
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- script: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts compile $(node -p process.arch) > .build/packagelockhash
|
||||
- script: mkdir -p .build && node build/azure-pipelines/common/computeNodeModulesCacheKey.ts quality $(node -p process.arch) > .build/packagelockhash
|
||||
displayName: Prepare node_modules cache key
|
||||
|
||||
- task: Cache@2
|
||||
@@ -46,9 +44,6 @@ jobs:
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
npm config set registry "$NPM_REGISTRY"
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$(npm config get userconfig)"
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
@@ -71,7 +66,38 @@ jobs:
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Install build dependencies
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
export VSCODE_SYSROOT_DIR=$(Build.SourcesDirectory)/.build/sysroots/glibc-2.28-gcc-8.5.0
|
||||
SYSROOT_ARCH="amd64" VSCODE_SYSROOT_PREFIX="-glibc-2.28-gcc-8.5.0" node -e 'import { getVSCodeSysroot } from "./build/linux/debian/install-sysroot.ts"; (async () => { await getVSCodeSysroot(process.env["SYSROOT_ARCH"]); })()'
|
||||
env:
|
||||
VSCODE_ARCH: x64
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download vscode sysroots
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
source ./build/azure-pipelines/linux/setup-env.sh
|
||||
node build/npm/preinstall.ts
|
||||
|
||||
for i in {1..5}; do # try 5 times
|
||||
npm ci && break
|
||||
if [ $i -eq 5 ]; then
|
||||
echo "Npm install failed too many times" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Npm install failed $i, trying again..."
|
||||
done
|
||||
env:
|
||||
npm_config_arch: x64
|
||||
VSCODE_ARCH: x64
|
||||
ELECTRON_SKIP_BINARY_DOWNLOAD: 1
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
@@ -93,43 +119,37 @@ jobs:
|
||||
- script: node build/azure-pipelines/distro/mixin-quality.ts
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: common/install-builtin-extensions.yml@self
|
||||
- script: node build/azure-pipelines/common/checkDistroCommit.ts
|
||||
displayName: Check distro commit
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
BUILD_SOURCEBRANCH: "$(Build.SourceBranch)"
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
|
||||
- script: npm exec -- npm-run-all2 -lp core-ci extensions-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
|
||||
- script: node build/azure-pipelines/common/checkCopilotChatCompatibility.ts --warn-only
|
||||
displayName: Check Copilot Chat compatibility
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
|
||||
- script: npm exec -- npm-run-all2 -lp core-ci hygiene eslint valid-layers-check define-class-fields-check vscode-dts-compile-check tsec-compile-check test-build-scripts
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile & Hygiene
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
- script: npm run download-builtin-extensions-cg
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download component details of built-in extensions
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
|
||||
[ -d "out-build" ] || { echo "ERROR: out-build folder is missing" >&2; exit 1; }
|
||||
[ -n "$(find out-build -mindepth 1 2>/dev/null | head -1)" ] || { echo "ERROR: out-build folder is empty" >&2; exit 1; }
|
||||
echo "out-build exists and is not empty"
|
||||
|
||||
ls -d out-vscode-* >/dev/null 2>&1 || { echo "ERROR: No out-vscode-* folders found" >&2; exit 1; }
|
||||
for folder in out-vscode-*; do
|
||||
[ -d "$folder" ] || { echo "ERROR: $folder is missing" >&2; exit 1; }
|
||||
[ -n "$(find "$folder" -mindepth 1 2>/dev/null | head -1)" ] || { echo "ERROR: $folder is empty" >&2; exit 1; }
|
||||
echo "$folder exists and is not empty"
|
||||
done
|
||||
|
||||
echo "All required compilation folders checked."
|
||||
displayName: Validate compilation folders
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile smoke test suites (non-OSS)
|
||||
workingDirectory: test/smoke
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run compile
|
||||
displayName: Compile integration test suites (non-OSS)
|
||||
workingDirectory: test/integration/browser
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: "Component Detection"
|
||||
inputs:
|
||||
sourceScanPath: $(Build.SourcesDirectory)
|
||||
alertWarningLevel: Medium
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
|
||||
- task: AzureCLI@2
|
||||
displayName: Fetch secrets
|
||||
@@ -142,6 +162,7 @@ jobs:
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_TENANT_ID]$env:tenantId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_CLIENT_ID]$env:servicePrincipalId"
|
||||
Write-Host "##vso[task.setvariable variable=AZURE_ID_TOKEN;issecret=true]$env:idToken"
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
@@ -151,21 +172,4 @@ jobs:
|
||||
AZURE_ID_TOKEN="$(AZURE_ID_TOKEN)" \
|
||||
node build/azure-pipelines/upload-sourcemaps.ts
|
||||
displayName: Upload sourcemaps to Azure
|
||||
|
||||
- script: ./build/azure-pipelines/common/extract-telemetry.sh
|
||||
displayName: Generate lists of telemetry events
|
||||
|
||||
- script: tar -cz --exclude='.build/node_modules_cache' --exclude='.build/node_modules_list.txt' --exclude='.build/distro' -f $(Build.ArtifactStagingDirectory)/compilation.tar.gz $(ls -d .build out-* test/integration/browser/out test/smoke/out test/automation/out 2>/dev/null)
|
||||
displayName: Compress compilation artifact
|
||||
|
||||
- script: npm run download-builtin-extensions-cg
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Download component details of built-in extensions
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: "Component Detection"
|
||||
inputs:
|
||||
sourceScanPath: $(Build.SourcesDirectory)
|
||||
alertWarningLevel: Medium
|
||||
continueOnError: true
|
||||
condition: and(succeeded(), eq(lower(variables['VSCODE_PUBLISH']), 'true'))
|
||||
@@ -1,40 +0,0 @@
|
||||
jobs:
|
||||
- job: ValidationChecks
|
||||
displayName: Distro and Extension Validation
|
||||
timeoutInMinutes: 15
|
||||
steps:
|
||||
- template: ./common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- template: ./distro/download-distro.yml@self
|
||||
|
||||
- script: node build/azure-pipelines/distro/mixin-quality.ts
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- script: npm ci
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Install build dependencies
|
||||
|
||||
- script: node build/azure-pipelines/common/checkDistroCommit.ts
|
||||
displayName: Check distro commit
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
BUILD_SOURCEBRANCH: "$(Build.SourceBranch)"
|
||||
continueOnError: true
|
||||
|
||||
- script: node build/azure-pipelines/common/checkCopilotChatCompatibility.ts --warn-only
|
||||
displayName: Check Copilot Chat compatibility
|
||||
continueOnError: true
|
||||
@@ -33,15 +33,6 @@ jobs:
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- script: tar -xzf $(Build.ArtifactStagingDirectory)/compilation.tar.gz
|
||||
displayName: Extract compilation output
|
||||
|
||||
- script: node build/setup-npm-registry.ts $NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
@@ -118,6 +109,11 @@ jobs:
|
||||
|
||||
- template: ../common/install-builtin-extensions.yml@self
|
||||
|
||||
- script: npm run gulp core-ci
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp vscode-web-min-ci
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
parameters:
|
||||
- name: VSCODE_BUILD_WIN32
|
||||
type: boolean
|
||||
- name: VSCODE_BUILD_WIN32_ARM64
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
- job: WindowsCLISign
|
||||
timeoutInMinutes: 90
|
||||
templateContext:
|
||||
outputParentDirectory: $(Build.ArtifactStagingDirectory)/out
|
||||
outputs:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_win32_x64_cli.zip
|
||||
artifactName: vscode_cli_win32_x64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_win32_x64_cli
|
||||
sbomBuildDropPath: $(Build.BinariesDirectory)/sign/unsigned_vscode_cli_win32_x64_cli
|
||||
sbomPackageName: "VS Code Windows x64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_win32_arm64_cli.zip
|
||||
artifactName: vscode_cli_win32_arm64_cli
|
||||
displayName: Publish signed artifact with ID vscode_cli_win32_arm64_cli
|
||||
sbomBuildDropPath: $(Build.BinariesDirectory)/sign/unsigned_vscode_cli_win32_arm64_cli
|
||||
sbomPackageName: "VS Code Windows arm64 CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node.js"
|
||||
inputs:
|
||||
versionSource: fromFile
|
||||
versionFilePath: .nvmrc
|
||||
|
||||
- task: AzureKeyVault@2
|
||||
displayName: "Azure Key Vault: Get Secrets"
|
||||
inputs:
|
||||
azureSubscription: vscode
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- powershell: node build/setup-npm-registry.ts $env:NPM_REGISTRY build
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
# Set the private NPM registry to the global npmrc file
|
||||
# so that authentication works for subfolders like build/, remote/, extensions/ etc
|
||||
# which does not have their own .npmrc file
|
||||
exec { npm config set registry "$env:NPM_REGISTRY" }
|
||||
$NpmrcPath = (npm config get userconfig)
|
||||
echo "##vso[task.setvariable variable=NPMRC_PATH]$NpmrcPath"
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM
|
||||
|
||||
- task: npmAuthenticate@0
|
||||
inputs:
|
||||
workingFile: $(NPMRC_PATH)
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Authentication
|
||||
|
||||
- powershell: |
|
||||
. azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm ci }
|
||||
workingDirectory: build
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
retryCountOnTaskFailure: 5
|
||||
displayName: Install build dependencies
|
||||
|
||||
- template: ./steps/product-build-win32-cli-sign.yml@self
|
||||
parameters:
|
||||
VSCODE_CLI_ARTIFACTS:
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32, true) }}:
|
||||
- unsigned_vscode_cli_win32_x64_cli
|
||||
- ${{ if eq(parameters.VSCODE_BUILD_WIN32_ARM64, true) }}:
|
||||
- unsigned_vscode_cli_win32_arm64_cli
|
||||
@@ -9,22 +9,23 @@ parameters:
|
||||
|
||||
jobs:
|
||||
- job: WindowsCLI_${{ upper(parameters.VSCODE_ARCH) }}
|
||||
displayName: Windows (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
displayName: Windows CLI (${{ upper(parameters.VSCODE_ARCH) }})
|
||||
pool:
|
||||
name: 1es-windows-2022-x64
|
||||
os: windows
|
||||
timeoutInMinutes: 30
|
||||
timeoutInMinutes: 90
|
||||
variables:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
templateContext:
|
||||
outputs:
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- output: pipelineArtifact
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli artifact
|
||||
sbomEnabled: false
|
||||
isProduction: false
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/out/vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish vscode_cli_win32_$(VSCODE_ARCH)_cli artifact
|
||||
sbomBuildDropPath: $(Build.ArtifactStagingDirectory)/sign
|
||||
sbomPackageName: "VS Code Windows $(VSCODE_ARCH) CLI"
|
||||
sbomPackageVersion: $(Build.SourceVersion)
|
||||
|
||||
steps:
|
||||
- template: ../common/checkout.yml@self
|
||||
@@ -75,3 +76,54 @@ jobs:
|
||||
${{ if eq(parameters.VSCODE_ARCH, 'arm64') }}:
|
||||
RUSTFLAGS: "-Ctarget-feature=+crt-static -Clink-args=/guard:cf -Clink-args=/CETCOMPAT:NO"
|
||||
CFLAGS: "/guard:cf /Qspectre"
|
||||
|
||||
- ${{ if not(parameters.VSCODE_CHECK_ONLY) }}:
|
||||
- template: ../common/publish-artifact.yml@self
|
||||
parameters:
|
||||
targetPath: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
artifactName: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
displayName: Publish unsigned CLI
|
||||
sbomEnabled: false
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract unsigned CLI
|
||||
inputs:
|
||||
archiveFilePatterns: $(Build.ArtifactStagingDirectory)/unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
destinationFolder: $(Build.ArtifactStagingDirectory)/sign
|
||||
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$EsrpCodeSigningTool = (gci -directory -filter EsrpCodeSigning_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName
|
||||
$Version = (gci -directory $EsrpCodeSigningTool | Select-Object -last 1).FullName
|
||||
echo "##vso[task.setvariable variable=EsrpCliDllPath]$Version\net6.0\esrpcli.dll"
|
||||
displayName: Find ESRP CLI
|
||||
|
||||
- powershell: node build\azure-pipelines\common\sign.ts $env:EsrpCliDllPath sign-windows $(Build.ArtifactStagingDirectory)/sign "*.exe"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Archive signed CLI
|
||||
inputs:
|
||||
rootFolderOrFile: $(Build.ArtifactStagingDirectory)/sign
|
||||
includeRootFolder: false
|
||||
archiveType: zip
|
||||
archiveFile: $(Build.ArtifactStagingDirectory)/out/vscode_cli_win32_$(VSCODE_ARCH)_cli.zip
|
||||
|
||||
@@ -21,6 +21,7 @@ jobs:
|
||||
timeoutInMinutes: 90
|
||||
variables:
|
||||
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
|
||||
BUILDS_API_URL: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/
|
||||
templateContext:
|
||||
outputParentDirectory: $(Build.ArtifactStagingDirectory)/out
|
||||
outputs:
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
parameters:
|
||||
- name: VSCODE_CLI_ARTIFACTS
|
||||
type: object
|
||||
default: []
|
||||
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
inputs:
|
||||
version: 6.x
|
||||
|
||||
- task: EsrpCodeSigning@5
|
||||
inputs:
|
||||
UseMSIAuthentication: true
|
||||
ConnectedServiceName: vscode-esrp
|
||||
AppRegistrationClientId: $(ESRP_CLIENT_ID)
|
||||
AppRegistrationTenantId: $(ESRP_TENANT_ID)
|
||||
AuthAKVName: vscode-esrp
|
||||
AuthSignCertName: esrp-sign
|
||||
FolderPath: .
|
||||
Pattern: noop
|
||||
displayName: 'Install ESRP Tooling'
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$EsrpCodeSigningTool = (gci -directory -filter EsrpCodeSigning_* $(Agent.RootDirectory)\_tasks | Select-Object -last 1).FullName
|
||||
$Version = (gci -directory $EsrpCodeSigningTool | Select-Object -last 1).FullName
|
||||
echo "##vso[task.setvariable variable=EsrpCliDllPath]$Version\net6.0\esrpcli.dll"
|
||||
displayName: Find ESRP CLI
|
||||
|
||||
- ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
displayName: Download artifact
|
||||
inputs:
|
||||
artifact: ${{ target }}
|
||||
path: $(Build.BinariesDirectory)/pkg/${{ target }}
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract artifact
|
||||
inputs:
|
||||
archiveFilePatterns: $(Build.BinariesDirectory)/pkg/${{ target }}/*.zip
|
||||
destinationFolder: $(Build.BinariesDirectory)/sign/${{ target }}
|
||||
|
||||
- powershell: node build\azure-pipelines\common\sign.ts $env:EsrpCliDllPath sign-windows $(Build.BinariesDirectory)/sign "*.exe"
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: ✍️ Codesign
|
||||
|
||||
- ${{ each target in parameters.VSCODE_CLI_ARTIFACTS }}:
|
||||
- powershell: |
|
||||
$ASSET_ID = "${{ target }}".replace("unsigned_", "");
|
||||
echo "##vso[task.setvariable variable=ASSET_ID]$ASSET_ID"
|
||||
displayName: Set asset id variable
|
||||
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Archive signed files
|
||||
inputs:
|
||||
rootFolderOrFile: $(Build.BinariesDirectory)/sign/${{ target }}
|
||||
includeRootFolder: false
|
||||
archiveType: zip
|
||||
archiveFile: $(Build.ArtifactStagingDirectory)/out/$(ASSET_ID).zip
|
||||
@@ -37,18 +37,6 @@ steps:
|
||||
KeyVaultName: vscode-build-secrets
|
||||
SecretsFilter: "github-distro-mixin-password"
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: Compilation
|
||||
path: $(Build.ArtifactStagingDirectory)
|
||||
displayName: Download compilation output
|
||||
|
||||
- task: ExtractFiles@1
|
||||
displayName: Extract compilation output
|
||||
inputs:
|
||||
archiveFilePatterns: "$(Build.ArtifactStagingDirectory)/compilation.tar.gz"
|
||||
cleanDestinationFolder: false
|
||||
|
||||
- powershell: node build/setup-npm-registry.ts $env:NPM_REGISTRY
|
||||
condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none'))
|
||||
displayName: Setup NPM Registry
|
||||
@@ -114,11 +102,34 @@ steps:
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
displayName: Create node_modules archive
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- pwsh: npx deemon --detach --wait -- node build/azure-pipelines/common/waitForArtifacts.ts unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact (background)
|
||||
|
||||
- powershell: node build/azure-pipelines/distro/mixin-quality.ts
|
||||
displayName: Mixin distro quality
|
||||
|
||||
- template: ../../common/install-builtin-extensions.yml@self
|
||||
|
||||
- powershell: npm run gulp core-ci
|
||||
env:
|
||||
GITHUB_TOKEN: "$(github-distro-mixin-password)"
|
||||
displayName: Compile
|
||||
|
||||
- script: node build/azure-pipelines/common/extract-telemetry.ts
|
||||
displayName: Generate lists of telemetry events
|
||||
|
||||
- ${{ if or(eq(parameters.VSCODE_RUN_ELECTRON_TESTS, true), eq(parameters.VSCODE_RUN_BROWSER_TESTS, true), eq(parameters.VSCODE_RUN_REMOTE_TESTS, true)) }}:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run compile --prefix test/smoke }
|
||||
exec { npm run compile --prefix test/integration/browser }
|
||||
displayName: Compile test suites (non-OSS)
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- powershell: |
|
||||
npm run copy-policy-dto --prefix build
|
||||
@@ -181,6 +192,11 @@ steps:
|
||||
displayName: Build server (web)
|
||||
|
||||
- ${{ if ne(parameters.VSCODE_CIBUILD, true) }}:
|
||||
- pwsh: npx deemon --attach -- node build/azure-pipelines/common/waitForArtifacts.ts unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
displayName: Wait for CLI artifact
|
||||
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
artifact: unsigned_vscode_cli_win32_$(VSCODE_ARCH)_cli
|
||||
|
||||
@@ -28,7 +28,7 @@ async function main(buildDir?: string) {
|
||||
const filesToSkip = [
|
||||
'**/CodeResources',
|
||||
'**/Credits.rtf',
|
||||
'**/policies/{*.mobileconfig,**/*.plist}',
|
||||
'**/policies/{*.mobileconfig,**/*.plist}'
|
||||
];
|
||||
|
||||
await makeUniversalApp({
|
||||
|
||||
@@ -6,8 +6,9 @@ format = 'ULMO'
|
||||
badge_icon = {{BADGE_ICON}}
|
||||
background = {{BACKGROUND}}
|
||||
|
||||
# Volume size (None = auto-calculate)
|
||||
size = None
|
||||
# Volume size
|
||||
size = '1g'
|
||||
shrink = False
|
||||
|
||||
# Files and symlinks
|
||||
files = [{{APP_PATH}}]
|
||||
|
||||
@@ -95,6 +95,7 @@ const compilations = [
|
||||
|
||||
'.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json',
|
||||
'.vscode/extensions/vscode-selfhost-import-aid/tsconfig.json',
|
||||
'.vscode/extensions/vscode-extras/tsconfig.json',
|
||||
];
|
||||
|
||||
const getBaseUrl = (out: string) => `https://main.vscode-cdn.net/sourcemaps/${commit}/${out}`;
|
||||
@@ -289,19 +290,7 @@ export const compileAllExtensionsBuildTask = task.define('compile-extensions-bui
|
||||
));
|
||||
gulp.task(compileAllExtensionsBuildTask);
|
||||
|
||||
// This task is run in the compilation stage of the CI pipeline. We only compile the non-native extensions since those can be fully built regardless of platform.
|
||||
// This defers the native extensions to the platform specific stage of the CI pipeline.
|
||||
gulp.task(task.define('extensions-ci', task.series(compileNonNativeExtensionsBuildTask, compileExtensionMediaBuildTask)));
|
||||
|
||||
const compileExtensionsBuildPullRequestTask = task.define('compile-extensions-build-pr', task.series(
|
||||
cleanExtensionsBuildTask,
|
||||
bundleMarketplaceExtensionsBuildTask,
|
||||
task.define('bundle-extensions-build-pr', () => ext.packageAllLocalExtensionsStream(false, true).pipe(gulp.dest('.build'))),
|
||||
));
|
||||
gulp.task(compileExtensionsBuildPullRequestTask);
|
||||
|
||||
// This task is run in the compilation stage of the PR pipeline. We compile all extensions in it to verify compilation.
|
||||
gulp.task(task.define('extensions-ci-pr', task.series(compileExtensionsBuildPullRequestTask, compileExtensionMediaBuildTask)));
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -320,13 +309,6 @@ async function buildWebExtensions(isWatch: boolean): Promise<void> {
|
||||
{ ignore: ['**/node_modules'] }
|
||||
);
|
||||
|
||||
// Find all webpack configs, excluding those that will be esbuilt
|
||||
const esbuildExtensionDirs = new Set(esbuildConfigLocations.map(p => path.dirname(p)));
|
||||
const webpackConfigLocations = (await nodeUtil.promisify(glob)(
|
||||
path.join(extensionsPath, '**', 'extension-browser.webpack.config.js'),
|
||||
{ ignore: ['**/node_modules'] }
|
||||
)).filter(configPath => !esbuildExtensionDirs.has(path.dirname(configPath)));
|
||||
|
||||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
// Esbuild for extensions
|
||||
@@ -341,10 +323,5 @@ async function buildWebExtensions(isWatch: boolean): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
// Run webpack for remaining extensions
|
||||
if (webpackConfigLocations.length > 0) {
|
||||
promises.push(ext.webpackExtensions('packaging web extension', isWatch, webpackConfigLocations.map(configPath => ({ configPath }))));
|
||||
}
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
+47
-20
@@ -31,6 +31,7 @@ import minimist from 'minimist';
|
||||
import { compileBuildWithoutManglingTask, compileBuildWithManglingTask } from './gulpfile.compile.ts';
|
||||
import { compileNonNativeExtensionsBuildTask, compileNativeExtensionsBuildTask, compileAllExtensionsBuildTask, compileExtensionMediaBuildTask, cleanExtensionsBuildTask } from './gulpfile.extensions.ts';
|
||||
import { copyCodiconsTask } from './lib/compilation.ts';
|
||||
import type { EmbeddedProductInfo } from './lib/embeddedType.ts';
|
||||
import { useEsbuildTranspile } from './buildConfig.ts';
|
||||
import { promisify } from 'util';
|
||||
import globCallback from 'glob';
|
||||
@@ -236,6 +237,9 @@ function runTsGoTypeCheck(): Promise<void> {
|
||||
}
|
||||
|
||||
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
|
||||
const isCI = !!process.env['CI'] || !!process.env['BUILD_ARTIFACTSTAGINGDIRECTORY'] || !!process.env['GITHUB_WORKSPACE'];
|
||||
const useCdnSourceMapsForPackagingTasks = isCI;
|
||||
const stripSourceMapsInPackagingTasks = isCI;
|
||||
const minifyVSCodeTask = task.define('minify-vscode', task.series(
|
||||
bundleVSCodeTask,
|
||||
util.rimraf('out-vscode-min'),
|
||||
@@ -243,19 +247,17 @@ const minifyVSCodeTask = task.define('minify-vscode', task.series(
|
||||
));
|
||||
gulp.task(minifyVSCodeTask);
|
||||
|
||||
const coreCIOld = task.define('core-ci-old', task.series(
|
||||
gulp.task(task.define('core-ci-old', task.series(
|
||||
gulp.task('compile-build-with-mangling') as task.Task,
|
||||
task.parallel(
|
||||
gulp.task('minify-vscode') as task.Task,
|
||||
gulp.task('minify-vscode-reh') as task.Task,
|
||||
gulp.task('minify-vscode-reh-web') as task.Task,
|
||||
)
|
||||
));
|
||||
gulp.task(coreCIOld);
|
||||
)));
|
||||
|
||||
const coreCIEsbuild = task.define('core-ci-esbuild', task.series(
|
||||
gulp.task(task.define('core-ci', task.series(
|
||||
copyCodiconsTask,
|
||||
cleanExtensionsBuildTask,
|
||||
compileNonNativeExtensionsBuildTask,
|
||||
compileExtensionMediaBuildTask,
|
||||
writeISODate('out-build'),
|
||||
@@ -269,10 +271,7 @@ const coreCIEsbuild = task.define('core-ci-esbuild', task.series(
|
||||
task.define('esbuild-vscode-reh-min', () => runEsbuildBundle('out-vscode-reh-min', true, true, 'server', `${sourceMappingURLBase}/core`)),
|
||||
task.define('esbuild-vscode-reh-web-min', () => runEsbuildBundle('out-vscode-reh-web-min', true, true, 'server-web', `${sourceMappingURLBase}/core`)),
|
||||
)
|
||||
));
|
||||
gulp.task(coreCIEsbuild);
|
||||
|
||||
gulp.task(task.define('core-ci', useEsbuildTranspile ? coreCIEsbuild : coreCIOld));
|
||||
)));
|
||||
|
||||
const coreCIPR = task.define('core-ci-pr', task.series(
|
||||
gulp.task('compile-build-without-mangling') as task.Task,
|
||||
@@ -353,8 +352,11 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
|
||||
const extensions = gulp.src(['.build/extensions/**', ...platformSpecificBuiltInExtensionsExclusions], { base: '.build', dot: true });
|
||||
|
||||
const sourceFilterPattern = stripSourceMapsInPackagingTasks
|
||||
? ['**', '!**/*.{js,css}.map']
|
||||
: ['**'];
|
||||
const sources = es.merge(src, extensions)
|
||||
.pipe(filter(['**', '!**/*.{js,css}.map'], { dot: true }));
|
||||
.pipe(filter(sourceFilterPattern, { dot: true }));
|
||||
|
||||
let version = packageJson.version;
|
||||
const quality = (product as { quality?: string }).quality;
|
||||
@@ -389,7 +391,7 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
|
||||
const isInsiderOrExploration = quality === 'insider' || quality === 'exploration';
|
||||
const embedded = isInsiderOrExploration
|
||||
? (product as typeof product & { embedded?: { nameShort: string; nameLong: string; applicationName: string; dataFolderName: string; darwinBundleIdentifier: string; urlProtocol: string } }).embedded
|
||||
? (product as typeof product & { embedded?: EmbeddedProductInfo }).embedded
|
||||
: undefined;
|
||||
|
||||
const packageSubJsonStream = isInsiderOrExploration
|
||||
@@ -404,12 +406,9 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
const productSubJsonStream = embedded
|
||||
? gulp.src(['product.json'], { base: '.' })
|
||||
.pipe(jsonEditor((json: Record<string, unknown>) => {
|
||||
json.nameShort = embedded.nameShort;
|
||||
json.nameLong = embedded.nameLong;
|
||||
json.applicationName = embedded.applicationName;
|
||||
json.dataFolderName = embedded.dataFolderName;
|
||||
json.darwinBundleIdentifier = embedded.darwinBundleIdentifier;
|
||||
json.urlProtocol = embedded.urlProtocol;
|
||||
Object.keys(embedded).forEach(key => {
|
||||
json[key] = embedded[key as keyof EmbeddedProductInfo];
|
||||
});
|
||||
return json;
|
||||
}))
|
||||
.pipe(rename('product.sub.json'))
|
||||
@@ -427,8 +426,13 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
const productionDependencies = getProductionDependencies(root);
|
||||
const dependenciesSrc = productionDependencies.map(d => path.relative(root, d)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]).flat().concat('!**/*.mk');
|
||||
|
||||
const depFilterPattern = ['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock'];
|
||||
if (stripSourceMapsInPackagingTasks) {
|
||||
depFilterPattern.push('!**/*.{js,css}.map');
|
||||
}
|
||||
|
||||
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true })
|
||||
.pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.{js,css}.map']))
|
||||
.pipe(filter(depFilterPattern))
|
||||
.pipe(util.cleanNodeModules(path.join(import.meta.dirname, '.moduleignore')))
|
||||
.pipe(util.cleanNodeModules(path.join(import.meta.dirname, `.moduleignore.${process.platform}`)))
|
||||
.pipe(jsFilter)
|
||||
@@ -500,6 +504,9 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
'resources/win32/code_70x70.png',
|
||||
'resources/win32/code_150x150.png'
|
||||
], { base: '.' }));
|
||||
if (embedded) {
|
||||
all = es.merge(all, gulp.src('resources/win32/sessions.ico', { base: '.' }));
|
||||
}
|
||||
} else if (platform === 'linux') {
|
||||
const policyDest = gulp.src('.build/policies/linux/**', { base: '.build/policies/linux' })
|
||||
.pipe(rename(f => f.dirname = `policies/${f.dirname}`));
|
||||
@@ -523,6 +530,13 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
darwinMiniAppName: embedded.nameShort,
|
||||
darwinMiniAppBundleIdentifier: embedded.darwinBundleIdentifier,
|
||||
darwinMiniAppIcon: 'resources/darwin/sessions.icns',
|
||||
darwinMiniAppBundleURLTypes: [{
|
||||
role: 'Viewer',
|
||||
name: embedded.nameLong,
|
||||
urlSchemes: [embedded.urlProtocol]
|
||||
}],
|
||||
win32ProxyAppName: embedded.nameShort,
|
||||
win32ProxyIcon: 'resources/win32/sessions.ico',
|
||||
} : {})
|
||||
};
|
||||
|
||||
@@ -531,7 +545,13 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
.pipe(util.fixWin32DirectoryPermissions())
|
||||
.pipe(filter(['**', '!**/.github/**'], { dot: true })) // https://github.com/microsoft/vscode/issues/116523
|
||||
.pipe(electron(electronConfig))
|
||||
.pipe(filter(['**', '!LICENSE', '!version'], { dot: true }));
|
||||
.pipe(filter([
|
||||
'**',
|
||||
'!LICENSE',
|
||||
'!version',
|
||||
...(platform === 'darwin' && !isInsiderOrExploration ? ['!**/Contents/Applications'] : []),
|
||||
...(platform === 'win32' && !isInsiderOrExploration ? ['!**/electron_proxy.exe'] : []),
|
||||
], { dot: true }));
|
||||
|
||||
if (platform === 'linux') {
|
||||
result = es.merge(result, gulp.src('resources/completions/bash/code', { base: '.' })
|
||||
@@ -579,6 +599,7 @@ function packageTask(platform: string, arch: string, sourceFolderName: string, d
|
||||
}
|
||||
|
||||
result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
|
||||
.pipe(replace('@@VERSIONFOLDER@@', versionedResourcesFolder ? `${versionedResourcesFolder}\\` : ''))
|
||||
.pipe(rename(product.nameShort + '.VisualElementsManifest.xml')));
|
||||
|
||||
result = es.merge(result, gulp.src('.build/policies/win32/**', { base: '.build/policies/win32' })
|
||||
@@ -692,7 +713,13 @@ BUILD_TARGETS.forEach(buildTarget => {
|
||||
if (useEsbuildTranspile) {
|
||||
const esbuildBundleTask = task.define(
|
||||
`esbuild-bundle${dashed(platform)}${dashed(arch)}${dashed(minified)}`,
|
||||
() => runEsbuildBundle(sourceFolderName, !!minified, true, 'desktop', minified ? `${sourceMappingURLBase}/core` : undefined)
|
||||
() => runEsbuildBundle(
|
||||
sourceFolderName,
|
||||
!!minified,
|
||||
true,
|
||||
'desktop',
|
||||
minified && useCdnSourceMapsForPackagingTasks ? `${sourceMappingURLBase}/core` : undefined
|
||||
)
|
||||
);
|
||||
vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series(
|
||||
copyCodiconsTask,
|
||||
|
||||
@@ -33,7 +33,7 @@ const quality = (product as { quality?: string }).quality;
|
||||
const version = (quality && quality !== 'stable') ? `${packageJson.version}-${quality}` : packageJson.version;
|
||||
|
||||
// esbuild-based bundle for standalone web
|
||||
function runEsbuildBundle(outDir: string, minify: boolean, nls: boolean): Promise<void> {
|
||||
function runEsbuildBundle(outDir: string, minify: boolean, nls: boolean, sourceMapBaseUrl?: string): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const scriptPath = path.join(REPO_ROOT, 'build/next/index.ts');
|
||||
const args = [scriptPath, 'bundle', '--out', outDir, '--target', 'web'];
|
||||
@@ -44,6 +44,9 @@ function runEsbuildBundle(outDir: string, minify: boolean, nls: boolean): Promis
|
||||
if (nls) {
|
||||
args.push('--nls');
|
||||
}
|
||||
if (sourceMapBaseUrl) {
|
||||
args.push('--source-map-base-url', sourceMapBaseUrl);
|
||||
}
|
||||
|
||||
const proc = cp.spawn(process.execPath, args, {
|
||||
cwd: REPO_ROOT,
|
||||
@@ -164,8 +167,9 @@ const minifyVSCodeWebTask = task.define('minify-vscode-web-OLD', task.series(
|
||||
gulp.task(minifyVSCodeWebTask);
|
||||
|
||||
// esbuild-based tasks (new)
|
||||
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
|
||||
const esbuildBundleVSCodeWebTask = task.define('esbuild-vscode-web', () => runEsbuildBundle('out-vscode-web', false, true));
|
||||
const esbuildBundleVSCodeWebMinTask = task.define('esbuild-vscode-web-min', () => runEsbuildBundle('out-vscode-web-min', true, true));
|
||||
const esbuildBundleVSCodeWebMinTask = task.define('esbuild-vscode-web-min', () => runEsbuildBundle('out-vscode-web-min', true, true, `${sourceMappingURLBase}/core`));
|
||||
|
||||
function packageTask(sourceFolderName: string, destinationFolderName: string) {
|
||||
const destination = path.join(BUILD_ROOT, destinationFolderName);
|
||||
|
||||
@@ -14,6 +14,7 @@ import product from '../product.json' with { type: 'json' };
|
||||
import { getVersion } from './lib/getVersion.ts';
|
||||
import * as task from './lib/task.ts';
|
||||
import * as util from './lib/util.ts';
|
||||
import type { EmbeddedProductInfo } from './lib/embeddedType.ts';
|
||||
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
@@ -112,6 +113,17 @@ function buildWin32Setup(arch: string, target: string): task.CallbackTask {
|
||||
Quality: quality
|
||||
};
|
||||
|
||||
const isInsiderOrExploration = false;
|
||||
const embedded = isInsiderOrExploration
|
||||
? (product as typeof product & { embedded?: EmbeddedProductInfo }).embedded
|
||||
: undefined;
|
||||
|
||||
if (embedded) {
|
||||
definitions['ProxyExeBasename'] = embedded.nameShort;
|
||||
definitions['ProxyAppUserId'] = embedded.win32AppUserModelId;
|
||||
definitions['ProxyNameLong'] = embedded.nameLong;
|
||||
}
|
||||
|
||||
if (quality === 'stable' || quality === 'insider') {
|
||||
definitions['AppxPackage'] = `${quality === 'stable' ? 'code' : 'code_insider'}_${arch}.appx`;
|
||||
definitions['AppxPackageDll'] = `${quality === 'stable' ? 'code' : 'code_insider'}_explorer_command_${arch}.dll`;
|
||||
|
||||
+15
-1
@@ -5,9 +5,23 @@
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const root = path.join(import.meta.dirname, '..', '..');
|
||||
|
||||
/**
|
||||
* Get the ISO date for the build. Uses the git commit date of HEAD
|
||||
* so that independent builds on different machines produce the same
|
||||
* timestamp (required for deterministic builds, e.g. macOS Universal).
|
||||
*/
|
||||
export function getGitCommitDate(): string {
|
||||
try {
|
||||
return execSync('git log -1 --format=%cI HEAD', { cwd: root, encoding: 'utf8' }).trim();
|
||||
} catch {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a `outDir/date` file with the contents of the build
|
||||
* so that other tasks during the build process can use it and
|
||||
@@ -18,7 +32,7 @@ export function writeISODate(outDir: string) {
|
||||
const outDirectory = path.join(root, outDir);
|
||||
fs.mkdirSync(outDirectory, { recursive: true });
|
||||
|
||||
const date = new Date().toISOString();
|
||||
const date = getGitCommitDate();
|
||||
fs.writeFileSync(path.join(outDirectory, 'date'), date, 'utf8');
|
||||
|
||||
resolve();
|
||||
|
||||
+13
-8
@@ -2,12 +2,17 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
import withDefaults from '../shared.webpack.config.mjs';
|
||||
|
||||
export default withDefaults({
|
||||
context: import.meta.dirname,
|
||||
entry: {
|
||||
extension: './src/extension.ts',
|
||||
},
|
||||
});
|
||||
export type EmbeddedProductInfo = {
|
||||
nameShort: string;
|
||||
nameLong: string;
|
||||
applicationName: string;
|
||||
dataFolderName: string;
|
||||
darwinBundleIdentifier: string;
|
||||
urlProtocol: string;
|
||||
win32AppUserModelId: string;
|
||||
win32MutexName: string;
|
||||
win32RegValueName: string;
|
||||
win32NameVersion: string;
|
||||
win32VersionedUpdate: boolean;
|
||||
};
|
||||
+4
-204
@@ -20,10 +20,8 @@ import fancyLog from 'fancy-log';
|
||||
import ansiColors from 'ansi-colors';
|
||||
import buffer from 'gulp-buffer';
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
import webpack from 'webpack';
|
||||
import { getProductionDependencies } from './dependencies.ts';
|
||||
import { type IExtensionDefinition, getExtensionStream } from './builtInExtensions.ts';
|
||||
import { getVersion } from './getVersion.ts';
|
||||
import { fetchUrls, fetchGithub } from './fetch.ts';
|
||||
import { createTsgoStream, spawnTsgo } from './tsgo.ts';
|
||||
import vzip from 'gulp-vinyl-zip';
|
||||
@@ -32,8 +30,8 @@ import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const root = path.dirname(path.dirname(import.meta.dirname));
|
||||
const commit = getVersion(root);
|
||||
const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
|
||||
// const commit = getVersion(root);
|
||||
// const sourceMappingURLBase = `https://main.vscode-cdn.net/sourcemaps/${commit}`;
|
||||
|
||||
function minifyExtensionResources(input: Stream): Stream {
|
||||
const jsonFilter = filter(['**/*.json', '**/*.code-snippets'], { restore: true });
|
||||
@@ -65,32 +63,24 @@ function updateExtensionPackageJSON(input: Stream, update: (data: any) => any):
|
||||
.pipe(packageJsonFilter.restore);
|
||||
}
|
||||
|
||||
function fromLocal(extensionPath: string, forWeb: boolean, disableMangle: boolean): Stream {
|
||||
function fromLocal(extensionPath: string, forWeb: boolean, _disableMangle: boolean): Stream {
|
||||
|
||||
const esbuildConfigFileName = forWeb
|
||||
? 'esbuild.browser.mts'
|
||||
: 'esbuild.mts';
|
||||
|
||||
const webpackConfigFileName = forWeb
|
||||
? `extension-browser.webpack.config.js`
|
||||
: `extension.webpack.config.js`;
|
||||
|
||||
const hasEsbuild = fs.existsSync(path.join(extensionPath, esbuildConfigFileName));
|
||||
const hasWebpack = fs.existsSync(path.join(extensionPath, webpackConfigFileName));
|
||||
|
||||
let input: Stream;
|
||||
let isBundled = false;
|
||||
|
||||
if (hasEsbuild) {
|
||||
// Unlike webpack, esbuild only does bundling so we still want to run a separate type check step
|
||||
// Esbuild only does bundling so we still want to run a separate type check step
|
||||
input = es.merge(
|
||||
fromLocalEsbuild(extensionPath, esbuildConfigFileName),
|
||||
...getBuildRootsForExtension(extensionPath).map(root => typeCheckExtensionStream(root, forWeb)),
|
||||
);
|
||||
isBundled = true;
|
||||
} else if (hasWebpack) {
|
||||
input = fromLocalWebpack(extensionPath, webpackConfigFileName, disableMangle);
|
||||
isBundled = true;
|
||||
} else {
|
||||
input = fromLocalNormal(extensionPath);
|
||||
}
|
||||
@@ -122,132 +112,6 @@ export function typeCheckExtensionStream(extensionPath: string, forWeb: boolean)
|
||||
return createTsgoStream(tsconfigPath, { taskName: 'typechecking extension (tsgo)', noEmit: true });
|
||||
}
|
||||
|
||||
function fromLocalWebpack(extensionPath: string, webpackConfigFileName: string, disableMangle: boolean): Stream {
|
||||
const vsce = require('@vscode/vsce') as typeof import('@vscode/vsce');
|
||||
const webpack = require('webpack');
|
||||
const webpackGulp = require('webpack-stream');
|
||||
const result = es.through();
|
||||
|
||||
const packagedDependencies: string[] = [];
|
||||
const stripOutSourceMaps: string[] = [];
|
||||
const packageJsonConfig = require(path.join(extensionPath, 'package.json'));
|
||||
if (packageJsonConfig.dependencies) {
|
||||
const webpackConfig = require(path.join(extensionPath, webpackConfigFileName));
|
||||
const webpackRootConfig = webpackConfig.default;
|
||||
for (const key in webpackRootConfig.externals) {
|
||||
if (key in packageJsonConfig.dependencies) {
|
||||
packagedDependencies.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (webpackConfig.StripOutSourceMaps) {
|
||||
for (const filePath of webpackConfig.StripOutSourceMaps) {
|
||||
stripOutSourceMaps.push(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add prune support based on packagedDependencies to vsce.PackageManager.Npm similar
|
||||
// to vsce.PackageManager.Yarn.
|
||||
// A static analysis showed there are no webpack externals that are dependencies of the current
|
||||
// local extensions so we can use the vsce.PackageManager.None config to ignore dependencies list
|
||||
// as a temporary workaround.
|
||||
vsce.listFiles({ cwd: extensionPath, packageManager: vsce.PackageManager.None, packagedDependencies }).then(fileNames => {
|
||||
const files = fileNames
|
||||
.map(fileName => path.join(extensionPath, fileName))
|
||||
.map(filePath => new File({
|
||||
path: filePath,
|
||||
stat: fs.statSync(filePath),
|
||||
base: extensionPath,
|
||||
contents: fs.createReadStream(filePath)
|
||||
}));
|
||||
|
||||
// check for a webpack configuration files, then invoke webpack
|
||||
// and merge its output with the files stream.
|
||||
const webpackConfigLocations = (glob.sync(
|
||||
path.join(extensionPath, '**', webpackConfigFileName),
|
||||
{ ignore: ['**/node_modules'] }
|
||||
) as string[]);
|
||||
const webpackStreams = webpackConfigLocations.flatMap(webpackConfigPath => {
|
||||
|
||||
const webpackDone = (err: Error | undefined, stats: any) => {
|
||||
fancyLog(`Bundled extension: ${ansiColors.yellow(path.join(path.basename(extensionPath), path.relative(extensionPath, webpackConfigPath)))}...`);
|
||||
if (err) {
|
||||
result.emit('error', err);
|
||||
}
|
||||
const { compilation } = stats;
|
||||
if (compilation.errors.length > 0) {
|
||||
result.emit('error', compilation.errors.join('\n'));
|
||||
}
|
||||
if (compilation.warnings.length > 0) {
|
||||
result.emit('error', compilation.warnings.join('\n'));
|
||||
}
|
||||
};
|
||||
|
||||
const exportedConfig = require(webpackConfigPath).default;
|
||||
return (Array.isArray(exportedConfig) ? exportedConfig : [exportedConfig]).map(config => {
|
||||
const webpackConfig = {
|
||||
...config,
|
||||
...{ mode: 'production' }
|
||||
};
|
||||
if (disableMangle) {
|
||||
if (Array.isArray(config.module.rules)) {
|
||||
for (const rule of config.module.rules) {
|
||||
if (Array.isArray(rule.use)) {
|
||||
for (const use of rule.use) {
|
||||
if (String(use.loader).endsWith('mangle-loader.js')) {
|
||||
use.options.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const relativeOutputPath = path.relative(extensionPath, webpackConfig.output.path);
|
||||
|
||||
return webpackGulp(webpackConfig, webpack, webpackDone)
|
||||
.pipe(es.through(function (data) {
|
||||
data.stat = data.stat || {};
|
||||
data.base = extensionPath;
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(es.through(function (data: File) {
|
||||
// source map handling:
|
||||
// * rewrite sourceMappingURL
|
||||
// * save to disk so that upload-task picks this up
|
||||
if (path.extname(data.basename) === '.js') {
|
||||
if (stripOutSourceMaps.indexOf(data.relative) >= 0) { // remove source map
|
||||
const contents = (data.contents as Buffer).toString('utf8');
|
||||
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, ''), 'utf8');
|
||||
} else {
|
||||
const contents = (data.contents as Buffer).toString('utf8');
|
||||
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
|
||||
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
|
||||
}), 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('data', data);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
es.merge(...webpackStreams, es.readArray(files))
|
||||
// .pipe(es.through(function (data) {
|
||||
// // debug
|
||||
// console.log('out', data.path, data.contents.length);
|
||||
// this.emit('data', data);
|
||||
// }))
|
||||
.pipe(result);
|
||||
|
||||
}).catch(err => {
|
||||
console.error(extensionPath);
|
||||
console.error(packagedDependencies);
|
||||
result.emit('error', err);
|
||||
});
|
||||
|
||||
return result.pipe(createStatsStream(path.basename(extensionPath)));
|
||||
}
|
||||
|
||||
function fromLocalNormal(extensionPath: string): Stream {
|
||||
const vsce = require('@vscode/vsce') as typeof import('@vscode/vsce');
|
||||
@@ -649,70 +513,6 @@ export function translatePackageJSON(packageJSON: string, packageNLSPath: string
|
||||
|
||||
const extensionsPath = path.join(root, 'extensions');
|
||||
|
||||
export async function webpackExtensions(taskName: string, isWatch: boolean, webpackConfigLocations: { configPath: string; outputRoot?: string }[]) {
|
||||
const webpack = require('webpack') as typeof import('webpack');
|
||||
|
||||
const webpackConfigs: webpack.Configuration[] = [];
|
||||
|
||||
for (const { configPath, outputRoot } of webpackConfigLocations) {
|
||||
const configOrFnOrArray = require(configPath).default;
|
||||
function addConfig(configOrFnOrArray: webpack.Configuration | ((env: unknown, args: unknown) => webpack.Configuration) | webpack.Configuration[]) {
|
||||
for (const configOrFn of Array.isArray(configOrFnOrArray) ? configOrFnOrArray : [configOrFnOrArray]) {
|
||||
const config = typeof configOrFn === 'function' ? configOrFn({}, {}) : configOrFn;
|
||||
if (outputRoot) {
|
||||
config.output!.path = path.join(outputRoot, path.relative(path.dirname(configPath), config.output!.path!));
|
||||
}
|
||||
webpackConfigs.push(config);
|
||||
}
|
||||
}
|
||||
addConfig(configOrFnOrArray);
|
||||
}
|
||||
|
||||
function reporter(fullStats: any) {
|
||||
if (Array.isArray(fullStats.children)) {
|
||||
for (const stats of fullStats.children) {
|
||||
const outputPath = stats.outputPath;
|
||||
if (outputPath) {
|
||||
const relativePath = path.relative(extensionsPath, outputPath).replace(/\\/g, '/');
|
||||
const match = relativePath.match(/[^\/]+(\/server|\/client)?/);
|
||||
fancyLog(`Finished ${ansiColors.green(taskName)} ${ansiColors.cyan(match![0])} with ${stats.errors.length} errors.`);
|
||||
}
|
||||
if (Array.isArray(stats.errors)) {
|
||||
stats.errors.forEach((error: any) => {
|
||||
fancyLog.error(error);
|
||||
});
|
||||
}
|
||||
if (Array.isArray(stats.warnings)) {
|
||||
stats.warnings.forEach((warning: any) => {
|
||||
fancyLog.warn(warning);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (isWatch) {
|
||||
webpack(webpackConfigs).watch({}, (err, stats) => {
|
||||
if (err) {
|
||||
reject();
|
||||
} else {
|
||||
reporter(stats?.toJson());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
webpack(webpackConfigs).run((err, stats) => {
|
||||
if (err) {
|
||||
fancyLog.error(err);
|
||||
reject();
|
||||
} else {
|
||||
reporter(stats?.toJson());
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function esbuildExtensions(taskName: string, isWatch: boolean, scripts: { script: string; outputRoot?: string }[]): Promise<void> {
|
||||
function reporter(stdError: string, script: string) {
|
||||
const matches = (stdError || '').match(/\> (.+): error: (.+)?/g);
|
||||
|
||||
@@ -38,20 +38,6 @@
|
||||
}
|
||||
],
|
||||
"policies": [
|
||||
{
|
||||
"key": "chat.mcp.gallery.serviceUrl",
|
||||
"name": "McpGalleryServiceUrl",
|
||||
"category": "InteractiveSession",
|
||||
"minimumVersion": "1.101",
|
||||
"localization": {
|
||||
"description": {
|
||||
"key": "mcp.gallery.serviceUrl",
|
||||
"value": "Configure the MCP Gallery service URL to connect to"
|
||||
}
|
||||
},
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"key": "extensions.gallery.serviceUrl",
|
||||
"name": "ExtensionGalleryServiceUrl",
|
||||
@@ -66,6 +52,20 @@
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"key": "chat.mcp.gallery.serviceUrl",
|
||||
"name": "McpGalleryServiceUrl",
|
||||
"category": "InteractiveSession",
|
||||
"minimumVersion": "1.101",
|
||||
"localization": {
|
||||
"description": {
|
||||
"key": "mcp.gallery.serviceUrl",
|
||||
"value": "Configure the MCP Gallery service URL to connect to"
|
||||
}
|
||||
},
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
{
|
||||
"key": "extensions.allowed",
|
||||
"name": "AllowedExtensions",
|
||||
@@ -286,6 +286,20 @@
|
||||
},
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "workbench.browser.enableChatTools",
|
||||
"name": "BrowserChatTools",
|
||||
"category": "InteractiveSession",
|
||||
"minimumVersion": "1.110",
|
||||
"localization": {
|
||||
"description": {
|
||||
"key": "browser.enableChatTools",
|
||||
"value": "When enabled, chat agents can use browser tools to open and interact with pages in the Integrated Browser."
|
||||
}
|
||||
},
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"--vscode-activityErrorBadge-foreground",
|
||||
"--vscode-activityWarningBadge-background",
|
||||
"--vscode-activityWarningBadge-foreground",
|
||||
"--vscode-agentFeedbackInputWidget-border",
|
||||
"--vscode-agentSessionReadIndicator-foreground",
|
||||
"--vscode-agentSessionSelectedBadge-border",
|
||||
"--vscode-agentSessionSelectedUnfocusedBadge-border",
|
||||
@@ -35,6 +36,7 @@
|
||||
"--vscode-breadcrumb-focusForeground",
|
||||
"--vscode-breadcrumb-foreground",
|
||||
"--vscode-breadcrumbPicker-background",
|
||||
"--vscode-browser-border",
|
||||
"--vscode-button-background",
|
||||
"--vscode-button-border",
|
||||
"--vscode-button-foreground",
|
||||
@@ -644,6 +646,8 @@
|
||||
"--vscode-searchEditor-findMatchBorder",
|
||||
"--vscode-searchEditor-textInputBorder",
|
||||
"--vscode-selection-background",
|
||||
"--vscode-sessionsUpdateButton-downloadedBackground",
|
||||
"--vscode-sessionsUpdateButton-downloadingBackground",
|
||||
"--vscode-settings-checkboxBackground",
|
||||
"--vscode-settings-checkboxBorder",
|
||||
"--vscode-settings-checkboxForeground",
|
||||
@@ -968,6 +972,14 @@
|
||||
"--vscode-repl-line-height",
|
||||
"--vscode-sash-hover-size",
|
||||
"--vscode-sash-size",
|
||||
"--vscode-shadow-active-tab",
|
||||
"--vscode-shadow-depth-x",
|
||||
"--vscode-shadow-depth-y",
|
||||
"--vscode-shadow-hover",
|
||||
"--vscode-shadow-lg",
|
||||
"--vscode-shadow-md",
|
||||
"--vscode-shadow-sm",
|
||||
"--vscode-shadow-xl",
|
||||
"--vscode-testing-coverage-lineHeight",
|
||||
"--vscode-editorStickyScroll-scrollableWidth",
|
||||
"--vscode-editorStickyScroll-foldingOpacityTransition",
|
||||
@@ -998,6 +1010,7 @@
|
||||
"--text-link-decoration",
|
||||
"--vscode-action-item-auto-timeout",
|
||||
"--monaco-editor-warning-decoration",
|
||||
"--animation-angle",
|
||||
"--animation-opacity",
|
||||
"--chat-setup-dialog-glow-angle",
|
||||
"--vscode-chat-font-family",
|
||||
|
||||
+54
-17
@@ -7,11 +7,13 @@ import * as esbuild from 'esbuild';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import glob from 'glob';
|
||||
import gulpWatch from '../lib/watch/index.ts';
|
||||
import { nlsPlugin, createNLSCollector, finalizeNLS, postProcessNLS } from './nls-plugin.ts';
|
||||
import { convertPrivateFields, adjustSourceMap, type ConvertPrivateFieldsResult } from './private-to-property.ts';
|
||||
import { getVersion } from '../lib/getVersion.ts';
|
||||
import { getGitCommitDate } from '../lib/date.ts';
|
||||
import product from '../../product.json' with { type: 'json' };
|
||||
import packageJson from '../../package.json' with { type: 'json' };
|
||||
import { useEsbuildTranspile } from '../buildConfig.ts';
|
||||
@@ -72,7 +74,8 @@ const extensionHostEntryPoints = [
|
||||
];
|
||||
|
||||
function isExtensionHostBundle(filePath: string): boolean {
|
||||
return extensionHostEntryPoints.some(ep => filePath.endsWith(`${ep}.js`));
|
||||
const normalized = filePath.replaceAll('\\', '/');
|
||||
return extensionHostEntryPoints.some(ep => normalized.endsWith(`${ep}.js`));
|
||||
}
|
||||
|
||||
// Workers - shared between targets
|
||||
@@ -419,13 +422,13 @@ function scanBuiltinExtensions(extensionsRoot: string): Array<IScannedBuiltinExt
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date from the out directory date file, or return current date.
|
||||
* Get the date from the out directory date file, or return the git commit date.
|
||||
*/
|
||||
function readISODate(outDir: string): string {
|
||||
try {
|
||||
return fs.readFileSync(path.join(REPO_ROOT, outDir, 'date'), 'utf8');
|
||||
} catch {
|
||||
return new Date().toISOString();
|
||||
return getGitCommitDate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,10 +726,19 @@ async function transpile(outDir: string, excludeTests: boolean): Promise<void> {
|
||||
async function bundle(outDir: string, doMinify: boolean, doNls: boolean, doManglePrivates: boolean, target: BuildTarget, sourceMapBaseUrl?: string): Promise<void> {
|
||||
await cleanDir(outDir);
|
||||
|
||||
// Write build date file (used by packaging to embed in product.json)
|
||||
// Write build date file (used by packaging to embed in product.json).
|
||||
// Reuse the date from out-build/date if it exists (written by the gulp
|
||||
// writeISODate task) so that all parallel bundle outputs share the same
|
||||
// timestamp - this is required for deterministic builds (e.g. macOS Universal).
|
||||
const outDirPath = path.join(REPO_ROOT, outDir);
|
||||
await fs.promises.mkdir(outDirPath, { recursive: true });
|
||||
await fs.promises.writeFile(path.join(outDirPath, 'date'), new Date().toISOString(), 'utf8');
|
||||
let buildDate: string;
|
||||
try {
|
||||
buildDate = await fs.promises.readFile(path.join(REPO_ROOT, 'out-build', 'date'), 'utf8');
|
||||
} catch {
|
||||
buildDate = getGitCommitDate();
|
||||
}
|
||||
await fs.promises.writeFile(path.join(outDirPath, 'date'), buildDate, 'utf8');
|
||||
|
||||
console.log(`[bundle] ${SRC_DIR} → ${outDir} (target: ${target})${doMinify ? ' (minify)' : ''}${doNls ? ' (nls)' : ''}${doManglePrivates ? ' (mangle-privates)' : ''}`);
|
||||
const t1 = Date.now();
|
||||
@@ -885,6 +897,13 @@ ${tslib}`,
|
||||
const mangleStats: { file: string; result: ConvertPrivateFieldsResult }[] = [];
|
||||
// Map from JS file path to pre-mangle content + edits, for source map adjustment
|
||||
const mangleEdits = new Map<string, { preMangleCode: string; edits: readonly import('./private-to-property.ts').TextEdit[] }>();
|
||||
// Map from JS file path to pre-NLS content + edits, for source map adjustment
|
||||
const nlsEdits = new Map<string, { preNLSCode: string; edits: readonly import('./private-to-property.ts').TextEdit[] }>();
|
||||
// Defer .map files until all .js files are processed, because esbuild may
|
||||
// emit the .map file in a different build result than the .js file (e.g.
|
||||
// code-split chunks), and we need the NLS/mangle edits from the .js pass
|
||||
// to be available when adjusting the .map.
|
||||
const deferredMaps: { path: string; text: string; contents: Uint8Array }[] = [];
|
||||
for (const { result } of buildResults) {
|
||||
if (!result.outputFiles) {
|
||||
continue;
|
||||
@@ -913,7 +932,12 @@ ${tslib}`,
|
||||
|
||||
// Apply NLS post-processing if enabled (JS only)
|
||||
if (file.path.endsWith('.js') && doNls && indexMap.size > 0) {
|
||||
content = postProcessNLS(content, indexMap, preserveEnglish);
|
||||
const preNLSCode = content;
|
||||
const nlsResult = postProcessNLS(content, indexMap, preserveEnglish);
|
||||
content = nlsResult.code;
|
||||
if (nlsResult.edits.length > 0) {
|
||||
nlsEdits.set(file.path, { preNLSCode, edits: nlsResult.edits });
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite sourceMappingURL to CDN URL if configured
|
||||
@@ -931,16 +955,8 @@ ${tslib}`,
|
||||
|
||||
await fs.promises.writeFile(file.path, content);
|
||||
} else if (file.path.endsWith('.map')) {
|
||||
// Source maps may need adjustment if private fields were mangled
|
||||
const jsPath = file.path.replace(/\.map$/, '');
|
||||
const editInfo = mangleEdits.get(jsPath);
|
||||
if (editInfo) {
|
||||
const mapJson = JSON.parse(file.text);
|
||||
const adjusted = adjustSourceMap(mapJson, editInfo.preMangleCode, editInfo.edits);
|
||||
await fs.promises.writeFile(file.path, JSON.stringify(adjusted));
|
||||
} else {
|
||||
await fs.promises.writeFile(file.path, file.contents);
|
||||
}
|
||||
// Defer .map processing until all .js files have been handled
|
||||
deferredMaps.push({ path: file.path, text: file.text, contents: file.contents });
|
||||
} else {
|
||||
// Write other files (assets, etc.) as-is
|
||||
await fs.promises.writeFile(file.path, file.contents);
|
||||
@@ -949,6 +965,27 @@ ${tslib}`,
|
||||
bundled++;
|
||||
}
|
||||
|
||||
// Second pass: process deferred .map files now that all mangle/NLS edits
|
||||
// have been collected from .js processing above.
|
||||
for (const mapFile of deferredMaps) {
|
||||
const jsPath = mapFile.path.replace(/\.map$/, '');
|
||||
const mangle = mangleEdits.get(jsPath);
|
||||
const nls = nlsEdits.get(jsPath);
|
||||
|
||||
if (mangle || nls) {
|
||||
let mapJson = JSON.parse(mapFile.text);
|
||||
if (mangle) {
|
||||
mapJson = adjustSourceMap(mapJson, mangle.preMangleCode, mangle.edits);
|
||||
}
|
||||
if (nls) {
|
||||
mapJson = adjustSourceMap(mapJson, nls.preNLSCode, nls.edits);
|
||||
}
|
||||
await fs.promises.writeFile(mapFile.path, JSON.stringify(mapJson));
|
||||
} else {
|
||||
await fs.promises.writeFile(mapFile.path, mapFile.contents);
|
||||
}
|
||||
}
|
||||
|
||||
// Log mangle-privates stats
|
||||
if (doManglePrivates && mangleStats.length > 0) {
|
||||
let totalClasses = 0, totalFields = 0, totalEdits = 0, totalElapsed = 0;
|
||||
@@ -1128,7 +1165,7 @@ async function main(): Promise<void> {
|
||||
// Write build date file (used by packaging to embed in product.json)
|
||||
const outDirPath = path.join(REPO_ROOT, outDir);
|
||||
await fs.promises.mkdir(outDirPath, { recursive: true });
|
||||
await fs.promises.writeFile(path.join(outDirPath, 'date'), new Date().toISOString(), 'utf8');
|
||||
await fs.promises.writeFile(path.join(outDirPath, 'date'), getGitCommitDate(), 'utf8');
|
||||
|
||||
console.log(`[transpile] ${SRC_DIR} → ${outDir}${options.excludeTests ? ' (excluding tests)' : ''}`);
|
||||
const t1 = Date.now();
|
||||
|
||||
+80
-52
@@ -12,6 +12,7 @@ import {
|
||||
analyzeLocalizeCalls,
|
||||
parseLocalizeKeyOrValue
|
||||
} from '../lib/nls-analysis.ts';
|
||||
import type { TextEdit } from './private-to-property.ts';
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
@@ -148,12 +149,13 @@ export async function finalizeNLS(
|
||||
|
||||
/**
|
||||
* Post-processes a JavaScript file to replace NLS placeholders with indices.
|
||||
* Returns the transformed code and the edits applied (for source map adjustment).
|
||||
*/
|
||||
export function postProcessNLS(
|
||||
content: string,
|
||||
indexMap: Map<string, number>,
|
||||
preserveEnglish: boolean
|
||||
): string {
|
||||
): { code: string; edits: readonly TextEdit[] } {
|
||||
return replaceInOutput(content, indexMap, preserveEnglish);
|
||||
}
|
||||
|
||||
@@ -244,7 +246,7 @@ function generateNLSSourceMap(
|
||||
const generator = new SourceMapGenerator();
|
||||
generator.setSourceContent(filePath, originalSource);
|
||||
|
||||
const lineCount = originalSource.split('\n').length;
|
||||
const lines = originalSource.split('\n');
|
||||
|
||||
// Group edits by line
|
||||
const editsByLine = new Map<number, NLSEdit[]>();
|
||||
@@ -257,7 +259,7 @@ function generateNLSSourceMap(
|
||||
arr.push(edit);
|
||||
}
|
||||
|
||||
for (let line = 0; line < lineCount; line++) {
|
||||
for (let line = 0; line < lines.length; line++) {
|
||||
const smLine = line + 1; // source maps use 1-based lines
|
||||
|
||||
// Always map start of line
|
||||
@@ -273,7 +275,8 @@ function generateNLSSourceMap(
|
||||
|
||||
let cumulativeShift = 0;
|
||||
|
||||
for (const edit of lineEdits) {
|
||||
for (let i = 0; i < lineEdits.length; i++) {
|
||||
const edit = lineEdits[i];
|
||||
const origLen = edit.endCol - edit.startCol;
|
||||
|
||||
// Map start of edit: the replacement begins at the same original position
|
||||
@@ -285,12 +288,20 @@ function generateNLSSourceMap(
|
||||
|
||||
cumulativeShift += edit.newLength - origLen;
|
||||
|
||||
// Map content after edit: columns resume with the shift applied
|
||||
generator.addMapping({
|
||||
generated: { line: smLine, column: edit.endCol + cumulativeShift },
|
||||
original: { line: smLine, column: edit.endCol },
|
||||
source: filePath,
|
||||
});
|
||||
// Source maps don't interpolate columns — each query resolves to the
|
||||
// last segment with generatedColumn <= queryColumn. A single mapping
|
||||
// at edit-end would cause every subsequent column on this line to
|
||||
// collapse to that one original position. Add per-column identity
|
||||
// mappings from edit-end to the next edit (or end of line) so that
|
||||
// esbuild's source-map composition preserves fine-grained accuracy.
|
||||
const nextBound = i + 1 < lineEdits.length ? lineEdits[i + 1].startCol : lines[line].length;
|
||||
for (let origCol = edit.endCol; origCol < nextBound; origCol++) {
|
||||
generator.addMapping({
|
||||
generated: { line: smLine, column: origCol + cumulativeShift },
|
||||
original: { line: smLine, column: origCol },
|
||||
source: filePath,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -302,17 +313,19 @@ function replaceInOutput(
|
||||
content: string,
|
||||
indexMap: Map<string, number>,
|
||||
preserveEnglish: boolean
|
||||
): string {
|
||||
// Replace all placeholders in a single pass using regex
|
||||
// Two types of placeholders:
|
||||
// - %%NLS:moduleId#key%% for localize() - message replaced with null
|
||||
// - %%NLS2:moduleId#key%% for localize2() - message preserved
|
||||
// Note: esbuild may use single or double quotes, so we handle both
|
||||
): { code: string; edits: readonly TextEdit[] } {
|
||||
// Collect all matches first, then apply from back to front so that byte
|
||||
// offsets remain valid. Each match becomes a TextEdit in terms of the
|
||||
// ORIGINAL content offsets, which is what adjustSourceMap expects.
|
||||
|
||||
interface PendingEdit { start: number; end: number; replacement: string }
|
||||
const pending: PendingEdit[] = [];
|
||||
|
||||
if (preserveEnglish) {
|
||||
// Just replace the placeholder with the index (both NLS and NLS2)
|
||||
return content.replace(/["']%%NLS2?:([^%]+)%%["']/g, (match, inner) => {
|
||||
// Try NLS first, then NLS2
|
||||
const re = /["']%%NLS2?:([^%]+)%%["']/g;
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = re.exec(content)) !== null) {
|
||||
const inner = m[1];
|
||||
let placeholder = `%%NLS:${inner}%%`;
|
||||
let index = indexMap.get(placeholder);
|
||||
if (index === undefined) {
|
||||
@@ -320,45 +333,60 @@ function replaceInOutput(
|
||||
index = indexMap.get(placeholder);
|
||||
}
|
||||
if (index !== undefined) {
|
||||
return String(index);
|
||||
pending.push({ start: m.index, end: m.index + m[0].length, replacement: String(index) });
|
||||
}
|
||||
// Placeholder not found in map, leave as-is (shouldn't happen)
|
||||
return match;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// For NLS (localize): replace placeholder with index AND replace message with null
|
||||
// For NLS2 (localize2): replace placeholder with index, keep message
|
||||
// Note: Use (?:[^"\\]|\\.)* to properly handle escaped quotes like \" or \\
|
||||
// Note: esbuild may use single or double quotes, so we handle both
|
||||
|
||||
// First handle NLS (localize) - replace both key and message
|
||||
content = content.replace(
|
||||
/["']%%NLS:([^%]+)%%["'](\s*,\s*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/g,
|
||||
(match, inner, comma) => {
|
||||
const placeholder = `%%NLS:${inner}%%`;
|
||||
const index = indexMap.get(placeholder);
|
||||
if (index !== undefined) {
|
||||
return `${index}${comma}null`;
|
||||
}
|
||||
return match;
|
||||
// NLS (localize): replace placeholder with index AND replace message with null
|
||||
const reNLS = /["']%%NLS:([^%]+)%%["'](\s*,\s*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/g;
|
||||
let m: RegExpExecArray | null;
|
||||
while ((m = reNLS.exec(content)) !== null) {
|
||||
const inner = m[1];
|
||||
const comma = m[2];
|
||||
const placeholder = `%%NLS:${inner}%%`;
|
||||
const index = indexMap.get(placeholder);
|
||||
if (index !== undefined) {
|
||||
pending.push({ start: m.index, end: m.index + m[0].length, replacement: `${index}${comma}null` });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Then handle NLS2 (localize2) - replace only key, keep message
|
||||
content = content.replace(
|
||||
/["']%%NLS2:([^%]+)%%["']/g,
|
||||
(match, inner) => {
|
||||
const placeholder = `%%NLS2:${inner}%%`;
|
||||
const index = indexMap.get(placeholder);
|
||||
if (index !== undefined) {
|
||||
return String(index);
|
||||
}
|
||||
return match;
|
||||
// NLS2 (localize2): replace only key, keep message
|
||||
const reNLS2 = /["']%%NLS2:([^%]+)%%["']/g;
|
||||
while ((m = reNLS2.exec(content)) !== null) {
|
||||
const inner = m[1];
|
||||
const placeholder = `%%NLS2:${inner}%%`;
|
||||
const index = indexMap.get(placeholder);
|
||||
if (index !== undefined) {
|
||||
pending.push({ start: m.index, end: m.index + m[0].length, replacement: String(index) });
|
||||
}
|
||||
);
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
if (pending.length === 0) {
|
||||
return { code: content, edits: [] };
|
||||
}
|
||||
|
||||
// Sort by offset ascending, then apply back-to-front to keep offsets valid
|
||||
pending.sort((a, b) => a.start - b.start);
|
||||
|
||||
// Build TextEdit[] (in original-content coordinates) and apply edits
|
||||
const edits: TextEdit[] = [];
|
||||
for (const p of pending) {
|
||||
edits.push({ start: p.start, end: p.end, newText: p.replacement });
|
||||
}
|
||||
|
||||
// Apply edits using forward-scanning parts array — O(N+K) instead of
|
||||
// O(N*K) from repeated substring concatenation on large strings.
|
||||
const parts: string[] = [];
|
||||
let lastEnd = 0;
|
||||
for (const p of pending) {
|
||||
parts.push(content.substring(lastEnd, p.start));
|
||||
parts.push(p.replacement);
|
||||
lastEnd = p.end;
|
||||
}
|
||||
parts.push(content.substring(lastEnd));
|
||||
|
||||
return { code: parts.join(''), edits };
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -220,15 +220,53 @@ export function adjustSourceMap(
|
||||
return sourceMapJson;
|
||||
}
|
||||
|
||||
// Build a line-offset table for the original code to convert byte offsets to line/column
|
||||
const lineStarts: number[] = [0];
|
||||
for (let i = 0; i < originalCode.length; i++) {
|
||||
if (originalCode.charCodeAt(i) === 10 /* \n */) {
|
||||
lineStarts.push(i + 1);
|
||||
}
|
||||
// Build line-offset tables for the original code and the code after edits.
|
||||
// When edits span newlines (e.g. NLS replacing a multi-line template literal
|
||||
// with `null`), subsequent lines shift up and columns change. We handle this
|
||||
// by converting each mapping's old generated (line, col) to a byte offset,
|
||||
// adjusting the offset for the edits, then converting back to (line, col) in
|
||||
// the post-edit coordinate system.
|
||||
|
||||
const oldLineStarts = buildLineStarts(originalCode);
|
||||
const newLineStarts = buildLineStartsAfterEdits(originalCode, edits);
|
||||
|
||||
// Precompute cumulative byte-shift after each edit for binary search
|
||||
const n = edits.length;
|
||||
const editStarts: number[] = new Array(n);
|
||||
const editEnds: number[] = new Array(n);
|
||||
const cumShifts: number[] = new Array(n); // cumulative shift *after* edit[i]
|
||||
let cumShift = 0;
|
||||
for (let i = 0; i < n; i++) {
|
||||
editStarts[i] = edits[i].start;
|
||||
editEnds[i] = edits[i].end;
|
||||
cumShift += edits[i].newText.length - (edits[i].end - edits[i].start);
|
||||
cumShifts[i] = cumShift;
|
||||
}
|
||||
|
||||
function offsetToLineCol(offset: number): { line: number; col: number } {
|
||||
function adjustOffset(oldOff: number): number {
|
||||
// Binary search: find last edit with start <= oldOff
|
||||
let lo = 0, hi = n - 1;
|
||||
while (lo <= hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
if (editStarts[mid] <= oldOff) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid - 1;
|
||||
}
|
||||
}
|
||||
// hi = index of last edit where start <= oldOff, or -1 if none
|
||||
if (hi < 0) {
|
||||
return oldOff;
|
||||
}
|
||||
if (oldOff < editEnds[hi]) {
|
||||
// Inside edit range — clamp to edit start in new coordinates
|
||||
const prevShift = hi > 0 ? cumShifts[hi - 1] : 0;
|
||||
return editStarts[hi] + prevShift;
|
||||
}
|
||||
return oldOff + cumShifts[hi];
|
||||
}
|
||||
|
||||
function offsetToLineCol(lineStarts: readonly number[], offset: number): { line: number; col: number } {
|
||||
let lo = 0, hi = lineStarts.length - 1;
|
||||
while (lo < hi) {
|
||||
const mid = (lo + hi + 1) >> 1;
|
||||
@@ -241,23 +279,9 @@ export function adjustSourceMap(
|
||||
return { line: lo, col: offset - lineStarts[lo] };
|
||||
}
|
||||
|
||||
// Convert edits from byte offsets to per-line column shifts
|
||||
interface LineEdit { col: number; origLen: number; newLen: number }
|
||||
const editsByLine = new Map<number, LineEdit[]>();
|
||||
for (const edit of edits) {
|
||||
const pos = offsetToLineCol(edit.start);
|
||||
const origLen = edit.end - edit.start;
|
||||
let arr = editsByLine.get(pos.line);
|
||||
if (!arr) {
|
||||
arr = [];
|
||||
editsByLine.set(pos.line, arr);
|
||||
}
|
||||
arr.push({ col: pos.col, origLen, newLen: edit.newText.length });
|
||||
}
|
||||
|
||||
// Use source-map library to read, adjust, and write
|
||||
const consumer = new SourceMapConsumer(sourceMapJson);
|
||||
const generator = new SourceMapGenerator({ file: sourceMapJson.file });
|
||||
const generator = new SourceMapGenerator({ file: sourceMapJson.file, sourceRoot: sourceMapJson.sourceRoot });
|
||||
|
||||
// Copy sourcesContent
|
||||
for (let i = 0; i < sourceMapJson.sources.length; i++) {
|
||||
@@ -267,15 +291,19 @@ export function adjustSourceMap(
|
||||
}
|
||||
}
|
||||
|
||||
// Walk every mapping, adjust the generated column, and add to the new generator
|
||||
// Walk every mapping, convert old generated position → byte offset → adjust → new position
|
||||
consumer.eachMapping(mapping => {
|
||||
const lineEdits = editsByLine.get(mapping.generatedLine - 1); // 0-based for our data
|
||||
const adjustedCol = adjustColumn(mapping.generatedColumn, lineEdits);
|
||||
const oldLine0 = mapping.generatedLine - 1; // 0-based
|
||||
const oldOff = (oldLine0 < oldLineStarts.length
|
||||
? oldLineStarts[oldLine0]
|
||||
: oldLineStarts[oldLineStarts.length - 1]) + mapping.generatedColumn;
|
||||
|
||||
const newOff = adjustOffset(oldOff);
|
||||
const newPos = offsetToLineCol(newLineStarts, newOff);
|
||||
|
||||
// Some mappings may be unmapped (no original position/source) - skip those.
|
||||
if (mapping.source !== null && mapping.originalLine !== null && mapping.originalColumn !== null) {
|
||||
const newMapping: Mapping = {
|
||||
generated: { line: mapping.generatedLine, column: adjustedCol },
|
||||
generated: { line: newPos.line + 1, column: newPos.col },
|
||||
original: { line: mapping.originalLine, column: mapping.originalColumn },
|
||||
source: mapping.source,
|
||||
};
|
||||
@@ -283,25 +311,82 @@ export function adjustSourceMap(
|
||||
newMapping.name = mapping.name;
|
||||
}
|
||||
generator.addMapping(newMapping);
|
||||
} else {
|
||||
// Preserve unmapped segments (generated-only mappings with no original
|
||||
// position). These create essential "gaps" that prevent
|
||||
// originalPositionFor() from wrongly interpolating between distant
|
||||
// valid mappings on the same line in minified output.
|
||||
// eslint-disable-next-line local/code-no-dangerous-type-assertions
|
||||
generator.addMapping({
|
||||
generated: { line: newPos.line + 1, column: newPos.col },
|
||||
} as Mapping);
|
||||
}
|
||||
});
|
||||
|
||||
return JSON.parse(generator.toString());
|
||||
}
|
||||
|
||||
function adjustColumn(col: number, lineEdits: { col: number; origLen: number; newLen: number }[] | undefined): number {
|
||||
if (!lineEdits) {
|
||||
return col;
|
||||
}
|
||||
let shift = 0;
|
||||
for (const edit of lineEdits) {
|
||||
if (edit.col + edit.origLen <= col) {
|
||||
shift += edit.newLen - edit.origLen;
|
||||
} else if (edit.col < col) {
|
||||
return edit.col + shift;
|
||||
} else {
|
||||
function buildLineStarts(text: string): number[] {
|
||||
const starts: number[] = [0];
|
||||
let pos = 0;
|
||||
while (true) {
|
||||
const nl = text.indexOf('\n', pos);
|
||||
if (nl === -1) {
|
||||
break;
|
||||
}
|
||||
starts.push(nl + 1);
|
||||
pos = nl + 1;
|
||||
}
|
||||
return col + shift;
|
||||
return starts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute line starts for the code that results from applying `edits` to
|
||||
* `originalCode`, without materialising the full new string.
|
||||
*/
|
||||
function buildLineStartsAfterEdits(originalCode: string, edits: readonly TextEdit[]): number[] {
|
||||
const starts: number[] = [0];
|
||||
let oldPos = 0;
|
||||
let newPos = 0;
|
||||
|
||||
for (const edit of edits) {
|
||||
// Scan unchanged region [oldPos, edit.start) for newlines
|
||||
let from = oldPos;
|
||||
while (true) {
|
||||
const nl = originalCode.indexOf('\n', from);
|
||||
if (nl === -1 || nl >= edit.start) {
|
||||
break;
|
||||
}
|
||||
starts.push(newPos + (nl - oldPos) + 1);
|
||||
from = nl + 1;
|
||||
}
|
||||
newPos += edit.start - oldPos;
|
||||
|
||||
// Scan replacement text for newlines
|
||||
let replFrom = 0;
|
||||
while (true) {
|
||||
const nl = edit.newText.indexOf('\n', replFrom);
|
||||
if (nl === -1) {
|
||||
break;
|
||||
}
|
||||
starts.push(newPos + nl + 1);
|
||||
replFrom = nl + 1;
|
||||
}
|
||||
newPos += edit.newText.length;
|
||||
|
||||
oldPos = edit.end;
|
||||
}
|
||||
|
||||
// Scan remaining unchanged text after last edit
|
||||
let from = oldPos;
|
||||
while (true) {
|
||||
const nl = originalCode.indexOf('\n', from);
|
||||
if (nl === -1) {
|
||||
break;
|
||||
}
|
||||
starts.push(newPos + (nl - oldPos) + 1);
|
||||
from = nl + 1;
|
||||
}
|
||||
|
||||
return starts;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import { type RawSourceMap, SourceMapConsumer } from 'source-map';
|
||||
import { nlsPlugin, createNLSCollector, finalizeNLS, postProcessNLS } from '../nls-plugin.ts';
|
||||
import { adjustSourceMap } from '../private-to-property.ts';
|
||||
|
||||
// analyzeLocalizeCalls requires the import path to end with `/nls`
|
||||
const NLS_STUB = [
|
||||
@@ -36,7 +37,7 @@ interface BundleResult {
|
||||
async function bundleWithNLS(
|
||||
files: Record<string, string>,
|
||||
entryPoint: string,
|
||||
opts?: { postProcess?: boolean }
|
||||
opts?: { postProcess?: boolean; minify?: boolean }
|
||||
): Promise<BundleResult> {
|
||||
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'nls-sm-test-'));
|
||||
const srcDir = path.join(tmpDir, 'src');
|
||||
@@ -64,6 +65,7 @@ async function bundleWithNLS(
|
||||
packages: 'external',
|
||||
sourcemap: 'linked',
|
||||
sourcesContent: true,
|
||||
minify: opts?.minify ?? false,
|
||||
write: false,
|
||||
plugins: [
|
||||
nlsPlugin({ baseDir: srcDir, collector }),
|
||||
@@ -91,7 +93,16 @@ async function bundleWithNLS(
|
||||
// Optionally apply NLS post-processing (replaces placeholders with indices)
|
||||
if (opts?.postProcess) {
|
||||
const nlsResult = await finalizeNLS(collector, outDir);
|
||||
jsContent = postProcessNLS(jsContent, nlsResult.indexMap, false);
|
||||
const preNLSCode = jsContent;
|
||||
const nlsProcessed = postProcessNLS(jsContent, nlsResult.indexMap, false);
|
||||
jsContent = nlsProcessed.code;
|
||||
|
||||
// Adjust source map for NLS edits
|
||||
if (nlsProcessed.edits.length > 0) {
|
||||
const mapJson = JSON.parse(mapContent);
|
||||
const adjusted = adjustSourceMap(mapJson, preNLSCode, nlsProcessed.edits);
|
||||
mapContent = JSON.stringify(adjusted);
|
||||
}
|
||||
}
|
||||
|
||||
assert.ok(jsContent, 'Expected JS output');
|
||||
@@ -370,4 +381,82 @@ suite('NLS plugin source maps', () => {
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
test('post-processed NLS - column mappings correct after placeholder replacement', async () => {
|
||||
// NLS placeholders like "%%NLS:test/drift#k%%" are much longer than their
|
||||
// replacements (e.g. "0"). Without source map adjustment the columns for
|
||||
// tokens AFTER the replacement drift by the cumulative length delta.
|
||||
const source = [
|
||||
'import { localize } from "../vs/nls";', // 1
|
||||
'export const a = localize("k1", "Alpha"); export const MARKER = "FINDME";', // 2
|
||||
].join('\n');
|
||||
|
||||
const { js, map, cleanup } = await bundleWithNLS(
|
||||
{ 'test/drift.ts': source },
|
||||
'test/drift.ts',
|
||||
{ postProcess: true }
|
||||
);
|
||||
|
||||
try {
|
||||
assert.ok(!js.includes('%%NLS:'), 'Placeholders should be replaced');
|
||||
|
||||
const bundleLine = findLine(js, 'FINDME');
|
||||
const bundleCol = findColumn(js, '"FINDME"');
|
||||
const pos = map.originalPositionFor({ line: bundleLine, column: bundleCol });
|
||||
|
||||
assert.ok(pos.source, 'Should have source');
|
||||
assert.strictEqual(pos.line, 2, 'Should map to line 2');
|
||||
|
||||
const originalCol = findColumn(source, '"FINDME"');
|
||||
const columnDrift = Math.abs(pos.column! - originalCol);
|
||||
assert.ok(columnDrift <= 20,
|
||||
`Column drift after NLS post-processing should be small. ` +
|
||||
`Expected ~${originalCol}, got ${pos.column} (drift: ${columnDrift}). ` +
|
||||
`Large drift means postProcessNLS edits were not applied to the source map.`);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
test('minified bundle with NLS - end-to-end column mapping', async () => {
|
||||
// With minification, the entire output is (roughly) on one line.
|
||||
// Multiple NLS replacements compound their column shifts. A function
|
||||
// defined after several localize() calls must still map correctly.
|
||||
const source = [
|
||||
'import { localize } from "../vs/nls";', // 1
|
||||
'', // 2
|
||||
'export const a = localize("k1", "Alpha message");', // 3
|
||||
'export const b = localize("k2", "Bravo message that is quite long");', // 4
|
||||
'export const c = localize("k3", "Charlie");', // 5
|
||||
'export const d = localize("k4", "Delta is the fourth letter");', // 6
|
||||
'', // 7
|
||||
'export function computeResult(x: number): number {', // 8
|
||||
'\treturn x * 42;', // 9
|
||||
'}', // 10
|
||||
].join('\n');
|
||||
|
||||
const { js, map, cleanup } = await bundleWithNLS(
|
||||
{ 'test/minified.ts': source },
|
||||
'test/minified.ts',
|
||||
{ postProcess: true, minify: true }
|
||||
);
|
||||
|
||||
try {
|
||||
assert.ok(!js.includes('%%NLS:'), 'Placeholders should be replaced');
|
||||
|
||||
// Find the computeResult function in the minified output.
|
||||
// esbuild minifies `x * 42` and may rename the parameter, so
|
||||
// search for `*42` which survives both minification and renaming.
|
||||
const needle = '*42';
|
||||
const bundleLine = findLine(js, needle);
|
||||
const bundleCol = findColumn(js, needle);
|
||||
const pos = map.originalPositionFor({ line: bundleLine, column: bundleCol });
|
||||
|
||||
assert.ok(pos.source, 'Should have source for minified mapping');
|
||||
assert.strictEqual(pos.line, 9,
|
||||
`Should map "*42" back to line 9. Got line ${pos.line}.`);
|
||||
} finally {
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -439,6 +439,41 @@ suite('adjustSourceMap', () => {
|
||||
assert.strictEqual(pos.column, origGetValueCol, 'getValue column should match original');
|
||||
});
|
||||
|
||||
test('multi-line edit: removing newlines shifts subsequent lines up', () => {
|
||||
// Simulates the NLS scenario: a template literal with embedded newlines
|
||||
// is replaced with `null`, collapsing 3 lines into 1.
|
||||
const code = [
|
||||
'var a = "hello";', // line 0 (0-based)
|
||||
'var b = `line1', // line 1
|
||||
'line2', // line 2
|
||||
'line3`;', // line 3
|
||||
'var c = "world";', // line 4
|
||||
].join('\n');
|
||||
const map = createIdentitySourceMap(code, 'test.js');
|
||||
|
||||
// Replace the template literal `line1\nline2\nline3` with `null`
|
||||
// (keeps `var b = ` and `;` intact)
|
||||
const tplStart = code.indexOf('`line1');
|
||||
const tplEnd = code.indexOf('line3`') + 'line3`'.length;
|
||||
const edits = [{ start: tplStart, end: tplEnd, newText: 'null' }];
|
||||
|
||||
const result = adjustSourceMap(map, code, edits);
|
||||
const consumer = new SourceMapConsumer(result);
|
||||
|
||||
// After edit, code is:
|
||||
// "var a = \"hello\";\nvar b = null;\nvar c = \"world\";"
|
||||
// "var c" was on line 5 (1-based), now on line 3 (1-based) since 2 newlines removed
|
||||
|
||||
// 'var c' at original line 5, col 0 should now map at generated line 3
|
||||
const pos = consumer.originalPositionFor({ line: 3, column: 0 });
|
||||
assert.strictEqual(pos.line, 5, 'var c should map to original line 5');
|
||||
assert.strictEqual(pos.column, 0, 'var c column should be 0');
|
||||
|
||||
// 'var a' on line 1 should be unaffected
|
||||
const posA = consumer.originalPositionFor({ line: 1, column: 0 });
|
||||
assert.strictEqual(posA.line, 1, 'var a should still map to original line 1');
|
||||
});
|
||||
|
||||
test('brand check: #field in obj -> string replacement adjusts map', () => {
|
||||
const code = 'class C { #x; check(o) { return #x in o; } }';
|
||||
const map = createIdentitySourceMap(code, 'test.js');
|
||||
|
||||
+70
-5
@@ -37,7 +37,7 @@ In [gulpfile.vscode.ts](../gulpfile.vscode.ts#L228-L242), the `core-ci` task use
|
||||
- `runEsbuildTranspile()` → transpile command
|
||||
- `runEsbuildBundle()` → bundle command
|
||||
|
||||
Old gulp-based bundling renamed to `core-ci-OLD`.
|
||||
Old gulp-based bundling renamed to `core-ci-old`.
|
||||
|
||||
---
|
||||
|
||||
@@ -134,7 +134,7 @@ npm run gulp vscode-reh-web-darwin-arm64-min
|
||||
|
||||
1. **`BUILD_INSERT_PACKAGE_CONFIGURATION`** - Server bootstrap files ([bootstrap-meta.ts](../../src/bootstrap-meta.ts)) have this marker for package.json injection. Currently handled by [inlineMeta.ts](../lib/inlineMeta.ts) in the old build's packaging step.
|
||||
|
||||
2. **Mangling** - The new build doesn't do TypeScript-based mangling yet. Old `core-ci` with mangling is now `core-ci-OLD`.
|
||||
2. **Mangling** - The new build doesn't do TypeScript-based mangling yet. Old `core-ci` with mangling is now `core-ci-old`.
|
||||
|
||||
3. **Entry point duplication** - Entry points are duplicated between [buildfile.ts](../buildfile.ts) and [index.ts](index.ts). Consider consolidating.
|
||||
|
||||
@@ -222,13 +222,13 @@ Two categories of corruption:
|
||||
|
||||
2. **`--source-map-base-url` option** - Rewrites `sourceMappingURL` comments to point to CDN URLs.
|
||||
|
||||
3. **NLS plugin inline source maps** (`nls-plugin.ts`) - The `onLoad` handler now generates an inline source map (`//# sourceMappingURL=data:...`) mapping from NLS-transformed source back to original. esbuild composes this with its own bundle source map. `SourceMapGenerator.setSourceContent` embeds the original source so `sourcesContent` in the final `.map` has the real TypeScript. Tests in `test/nls-sourcemap.test.ts`.
|
||||
3. **NLS plugin inline source maps** (`nls-plugin.ts`) - The `onLoad` handler generates an inline source map (`//# sourceMappingURL=data:...`) mapping from NLS-transformed source back to original. esbuild composes this with its own bundle source map. `SourceMapGenerator.setSourceContent` embeds the original source so `sourcesContent` in the final `.map` has the real TypeScript. `generateNLSSourceMap` adds per-column identity mappings after each edit on a line so that esbuild's source-map composition preserves fine-grained column accuracy (source maps don't interpolate columns — they use binary search, so a single boundary mapping would collapse all subsequent columns to the edit-end position). Tests in `test/nls-sourcemap.test.ts`.
|
||||
|
||||
4. **`convertPrivateFields` source map adjustment** (`private-to-property.ts`) - `convertPrivateFields` returns its sorted edits as `TextEdit[]`. `adjustSourceMap()` uses `SourceMapConsumer` to walk every mapping, adjusts generated columns based on cumulative edit shifts per line, and rebuilds with `SourceMapGenerator`. The post-processing loop in `index.ts` saves pre-mangle content + edits per JS file, then applies `adjustSourceMap` to the corresponding `.map`. Tests in `test/private-to-property.test.ts`.
|
||||
|
||||
### Not Yet Fixed
|
||||
5. **`postProcessNLS` source map adjustment** (`nls-plugin.ts`, `index.ts`) — `postProcessNLS` now returns `{ code, edits }` where `edits` is a `TextEdit[]` tracking each replacement's byte offset. The bundle loop in `index.ts` chains `adjustSourceMap` calls: first for mangle edits, then for NLS edits, so both transforms are accurately reflected in the final `.map` file. Tests in `test/nls-sourcemap.test.ts`.
|
||||
|
||||
**`postProcessNLS` column drift** - Replaces NLS placeholders with short indices in bundled output without updating `.map` files. Shifts columns but never lines, so line-level debugging and crash reporting work correctly. Fixing would require tracking replacement offsets through regex matches and adjusting the source map, similar to `adjustSourceMap`.
|
||||
6. **`adjustSourceMap` unmapped segment preservation** (`private-to-property.ts`) — Previously, `adjustSourceMap()` silently dropped mappings where `source === null`. These unmapped segments create essential "gaps" that prevent `originalPositionFor()` from wrongly interpolating between distant valid mappings on the same minified line. Now emits them as generated-only mappings. Also preserves `sourceRoot` from the input map.
|
||||
|
||||
### Key Technical Details
|
||||
|
||||
@@ -241,6 +241,71 @@ Two categories of corruption:
|
||||
|
||||
**Plugin interaction:** Both the NLS plugin and `fileContentMapperPlugin` register `onLoad({ filter: /\.ts$/ })`. In esbuild, the first `onLoad` to return non-`undefined` wins. The NLS plugin is `unshift`ed (runs first), so files with NLS calls skip `fileContentMapperPlugin`. This is safe in practice since `product.ts` (which has `BUILD->INSERT_PRODUCT_CONFIGURATION`) has no localize calls.
|
||||
|
||||
### Still Broken — Full Production Build (`npm run gulp vscode-min`)
|
||||
|
||||
**Symptom:** Source maps are totally broken in the minified production build. E.g. a breakpoint at `src/vs/editor/browser/editorExtensions.ts` line 308 resolves to `src/vs/editor/common/cursor/cursorMoveCommands.ts` line 732 — a completely different file. This is **cross-file** mapping corruption, not just column drift.
|
||||
|
||||
**Status of unit tests:** The fixes above pass in isolated unit tests (small 1–2 file bundles via `esbuild.build` with `minify: true`). The tests verify column drift ≤ 20 and correct line mapping for single-file bundles with NLS. **183 tests pass, 0 failing.** But the full production build bundles hundreds of files into huge minified outputs (e.g. `workbench.desktop.main.js` at ~15 MB) and the source maps break at that scale.
|
||||
|
||||
**Suspected root causes (need investigation):**
|
||||
|
||||
1. **`generateNLSSourceMap` per-column identity mappings may overwhelm esbuild's source-map composition.** The fix added one mapping per column from edit-end to end-of-line (or next edit). For a long TypeScript line with a `localize()` call near the beginning, this generates hundreds of identity mappings per line. Across hundreds of files, the inline source maps embedded in `onLoad` responses may be extremely large. esbuild must compose these with its own source maps during bundling — it may hit limits, silently drop mappings, or produce incorrect composed maps at this scale. **Mitigation to try:** Instead of per-column mappings, use sparser "checkpoint" mappings (e.g., every N characters) or rely only on boundary mappings and accept some column drift within the NLS-transformed region. The old boundary-only approach was wrong (collapsed all downstream columns), but per-column may be the other extreme.
|
||||
|
||||
2. **`adjustSourceMap` may corrupt source indices in large minified bundles.** In a minified bundle, the entire output is on one or very few lines. `adjustSourceMap()` walks every mapping via `SourceMapConsumer.eachMapping()` and adjusts `generatedColumn` using `adjustColumn()`. But when thousands of mappings all share `generatedLine: 1` and there are hundreds of NLS edits on that same line, there may be sorting/ordering bugs: `eachMapping()` returns mappings in generated order by default, but `adjustColumn()` binary-searches through edits sorted by column. If edits cover regions that interleave with mappings from different source files, the cumulative shift calculation might produce wrong columns that then resolve to wrong source files.
|
||||
|
||||
3. **Chained `adjustSourceMap` calls (mangle → NLS) may compound errors.** After the first `adjustSourceMap` for mangle edits, the source map's generated columns are updated. The second call for NLS edits uses `nlsEdits` which were computed against `preNLSCode` — but `preNLSCode` is the post-mangle JS, which is what the first `adjustSourceMap` maps from. This chaining _should_ be correct, but needs verification at scale with a real minified bundle.
|
||||
|
||||
4. **The `source-map` v0.6.1 library may have precision issues with very large VLQ-encoded maps.** The bundled outputs have source maps with hundreds of thousands of mappings. The library is old (2017) and there may be numerical precision or sorting issues with very large maps. Consider testing with `source-map` v0.7+ or the Rust-based `@aspect-build/source-map`.
|
||||
|
||||
5. **Alternative approach: skip per-column NLS plugin mappings, fix only `postProcessNLS`.** The NLS plugin `onLoad` replaces `"key"` with `"%%NLS:longPlaceholder%%"` — a length change that only affects columns on affected lines. The subsequent `postProcessNLS` then replaces the long placeholder with a short index. If the `adjustSourceMap` for `postProcessNLS` is correct, it should compensate for both expansions (plugin expansion + post-process contraction). We might not need per-column mappings in `generateNLSSourceMap` at all — just the boundary mapping. The column will drift in the intermediate representation but `adjustSourceMap` for NLS should fix it. **This hypothesis needs testing.**
|
||||
|
||||
6. **Alternative approach: do NLS replacement purely in post-processing.** Skip the `onLoad` two-phase approach (placeholder insertion + post-processing replacement) entirely. Instead, run `postProcessNLS` as a single post-processing step that directly replaces `localize("key", "message")` → `localize(0, null)` in the bundled JS output, with proper source-map adjustment via `adjustSourceMap`. This avoids both the inline source map composition complexity and the two-step replacement. The downside is that post-processing must parse/regex-match real `localize()` calls (not easy placeholders), which is more fragile.
|
||||
|
||||
**Summary of fixes applied vs status:**
|
||||
|
||||
| Bug | Fix | Unit test | Production |
|
||||
|-----|-----|-----------|------------|
|
||||
| `generateNLSSourceMap` only had boundary mappings → columns collapsed | Added per-column identity mappings after each edit | Pass (drift: 0) | **Broken** — may overwhelm esbuild composition at scale |
|
||||
| `postProcessNLS` didn't track edits for source map adjustment | Returns `{ code, edits }`, chained in `index.ts` | Pass | **Broken** — `adjustSourceMap` may corrupt source indices on huge single-line minified output |
|
||||
| `adjustSourceMap` dropped unmapped segments | Preserves generated-only mappings + `sourceRoot` | Pass (no regressions) | **Broken** — same cross-file mapping issue |
|
||||
|
||||
**Files involved:**
|
||||
- `build/next/nls-plugin.ts` — `generateNLSSourceMap()` (per-column mappings), `postProcessNLS()` (returns edits), `replaceInOutput()` (regex replacement)
|
||||
- `build/next/private-to-property.ts` — `adjustSourceMap()` (column adjustment)
|
||||
- `build/next/index.ts` — bundle post-processing loop (lines ~899–975), chains adjustSourceMap calls
|
||||
- `build/next/test/nls-sourcemap.test.ts` — unit tests (pass but don't cover production-scale bundles)
|
||||
|
||||
**How to reproduce:**
|
||||
```bash
|
||||
npm run gulp vscode-min
|
||||
# Open out-vscode-min/ in a debugger, set breakpoints in editor files
|
||||
# Observe breakpoints resolve to wrong files
|
||||
```
|
||||
|
||||
**How to debug further:**
|
||||
```bash
|
||||
# 1. Build with just --nls (no mangle) to isolate NLS from mangle issues
|
||||
npx tsx build/next/index.ts bundle --nls --minify --target desktop --out out-debug
|
||||
|
||||
# 2. Build with just --mangle-privates (no NLS) to isolate mangle issues
|
||||
npx tsx build/next/index.ts bundle --mangle-privates --minify --target desktop --out out-debug
|
||||
|
||||
# 3. Build with neither (baseline — does esbuild's own map work?)
|
||||
npx tsx build/next/index.ts bundle --minify --target desktop --out out-debug
|
||||
|
||||
# 4. Compare .map files across the three builds to find where mappings diverge
|
||||
|
||||
# 5. Validate a specific mapping in the large bundle:
|
||||
node -e "
|
||||
const {SourceMapConsumer} = require('source-map');
|
||||
const fs = require('fs');
|
||||
const map = JSON.parse(fs.readFileSync('./out-debug/vs/workbench/workbench.desktop.main.js.map','utf8'));
|
||||
const c = new SourceMapConsumer(map);
|
||||
// Look up a known position and see which source file it resolves to
|
||||
console.log(c.originalPositionFor({line: 1, column: XXXX}));
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-hosting Setup
|
||||
|
||||
@@ -60,6 +60,7 @@ export const dirs = [
|
||||
'test/mcp',
|
||||
'.vscode/extensions/vscode-selfhost-import-aid',
|
||||
'.vscode/extensions/vscode-selfhost-test-provider',
|
||||
'.vscode/extensions/vscode-extras',
|
||||
];
|
||||
|
||||
if (existsSync(`${import.meta.dirname}/../../.build/distro/npm`)) {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as child_process from 'child_process';
|
||||
import { root, isUpToDate, forceInstallMessage } from './installStateHash.ts';
|
||||
|
||||
if (!process.argv.includes('--force') && isUpToDate()) {
|
||||
console.log(`\x1b[32mAll dependencies up to date.\x1b[0m ${forceInstallMessage}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const result = child_process.spawnSync(npm, ['install'], {
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
env: { ...process.env, VSCODE_FORCE_INSTALL: '1' },
|
||||
});
|
||||
|
||||
process.exit(result.status ?? 1);
|
||||
Generated
+4
-4
@@ -526,13 +526,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import { dirs } from './dirs.ts';
|
||||
|
||||
export const root = fs.realpathSync.native(path.dirname(path.dirname(import.meta.dirname)));
|
||||
export const stateFile = path.join(root, 'node_modules', '.postinstall-state');
|
||||
export const stateContentsFile = path.join(root, 'node_modules', '.postinstall-state-contents');
|
||||
export const forceInstallMessage = 'Run \x1b[36mnode build/npm/fast-install.ts --force\x1b[0m to force a full install.';
|
||||
|
||||
export function collectInputFiles(): string[] {
|
||||
const files: string[] = [];
|
||||
|
||||
for (const dir of dirs) {
|
||||
const base = dir === '' ? root : path.join(root, dir);
|
||||
for (const file of ['package.json', 'package-lock.json', '.npmrc']) {
|
||||
const filePath = path.join(base, file);
|
||||
if (fs.existsSync(filePath)) {
|
||||
files.push(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
files.push(path.join(root, '.nvmrc'));
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
export interface PostinstallState {
|
||||
readonly nodeVersion: string;
|
||||
readonly fileHashes: Record<string, string>;
|
||||
}
|
||||
|
||||
const packageJsonRelevantKeys = new Set([
|
||||
'name',
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'optionalDependencies',
|
||||
'peerDependencies',
|
||||
'peerDependenciesMeta',
|
||||
'overrides',
|
||||
'engines',
|
||||
'workspaces',
|
||||
'bundledDependencies',
|
||||
'bundleDependencies',
|
||||
]);
|
||||
|
||||
const packageLockJsonIgnoredKeys = new Set(['version']);
|
||||
|
||||
function normalizeFileContent(filePath: string): string {
|
||||
const raw = fs.readFileSync(filePath, 'utf8');
|
||||
const basename = path.basename(filePath);
|
||||
if (basename === 'package.json') {
|
||||
const json = JSON.parse(raw);
|
||||
const filtered: Record<string, unknown> = {};
|
||||
for (const key of packageJsonRelevantKeys) {
|
||||
// eslint-disable-next-line local/code-no-in-operator
|
||||
if (key in json) {
|
||||
filtered[key] = json[key];
|
||||
}
|
||||
}
|
||||
return JSON.stringify(filtered, null, '\t') + '\n';
|
||||
}
|
||||
if (basename === 'package-lock.json') {
|
||||
const json = JSON.parse(raw);
|
||||
for (const key of packageLockJsonIgnoredKeys) {
|
||||
delete json[key];
|
||||
}
|
||||
if (json.packages?.['']) {
|
||||
for (const key of packageLockJsonIgnoredKeys) {
|
||||
delete json.packages[''][key];
|
||||
}
|
||||
}
|
||||
return JSON.stringify(json, null, '\t') + '\n';
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function hashContent(content: string): string {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(content);
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
export function computeState(): PostinstallState {
|
||||
const fileHashes: Record<string, string> = {};
|
||||
for (const filePath of collectInputFiles()) {
|
||||
const key = path.relative(root, filePath);
|
||||
try {
|
||||
fileHashes[key] = hashContent(normalizeFileContent(filePath));
|
||||
} catch {
|
||||
// file may not be readable
|
||||
}
|
||||
}
|
||||
return { nodeVersion: process.versions.node, fileHashes };
|
||||
}
|
||||
|
||||
export function computeContents(): Record<string, string> {
|
||||
const fileContents: Record<string, string> = {};
|
||||
for (const filePath of collectInputFiles()) {
|
||||
try {
|
||||
fileContents[path.relative(root, filePath)] = normalizeFileContent(filePath);
|
||||
} catch {
|
||||
// file may not be readable
|
||||
}
|
||||
}
|
||||
return fileContents;
|
||||
}
|
||||
|
||||
export function readSavedState(): PostinstallState | undefined {
|
||||
try {
|
||||
const { nodeVersion, fileHashes } = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
|
||||
return { nodeVersion, fileHashes };
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function isUpToDate(): boolean {
|
||||
const saved = readSavedState();
|
||||
if (!saved) {
|
||||
return false;
|
||||
}
|
||||
const current = computeState();
|
||||
return saved.nodeVersion === current.nodeVersion
|
||||
&& JSON.stringify(saved.fileHashes) === JSON.stringify(current.fileHashes);
|
||||
}
|
||||
|
||||
export function readSavedContents(): Record<string, string> | undefined {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(stateContentsFile, 'utf8'));
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// When run directly, output state as JSON for tooling (e.g. the vscode-extras extension).
|
||||
if (import.meta.filename === process.argv[1]) {
|
||||
console.log(JSON.stringify({
|
||||
root,
|
||||
stateContentsFile,
|
||||
current: computeState(),
|
||||
saved: readSavedState(),
|
||||
files: [...collectInputFiles(), stateFile],
|
||||
}));
|
||||
}
|
||||
+143
-67
@@ -8,9 +8,9 @@ import path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as child_process from 'child_process';
|
||||
import { dirs } from './dirs.ts';
|
||||
import { root, stateFile, stateContentsFile, computeState, computeContents, isUpToDate } from './installStateHash.ts';
|
||||
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
const root = path.dirname(path.dirname(import.meta.dirname));
|
||||
const rootNpmrcConfigKeys = getNpmrcConfigKeys(path.join(root, '.npmrc'));
|
||||
|
||||
function log(dir: string, message: string) {
|
||||
@@ -35,24 +35,45 @@ function run(command: string, args: string[], opts: child_process.SpawnSyncOptio
|
||||
}
|
||||
}
|
||||
|
||||
function npmInstall(dir: string, opts?: child_process.SpawnSyncOptions) {
|
||||
opts = {
|
||||
function spawnAsync(command: string, args: string[], opts: child_process.SpawnOptions): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = child_process.spawn(command, args, { ...opts, stdio: ['ignore', 'pipe', 'pipe'] });
|
||||
let output = '';
|
||||
child.stdout?.on('data', (data: Buffer) => { output += data.toString(); });
|
||||
child.stderr?.on('data', (data: Buffer) => { output += data.toString(); });
|
||||
child.on('error', reject);
|
||||
child.on('close', (code) => {
|
||||
if (code !== 0) {
|
||||
reject(new Error(`Process exited with code: ${code}\n${output}`));
|
||||
} else {
|
||||
resolve(output);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function npmInstallAsync(dir: string, opts?: child_process.SpawnOptions): Promise<void> {
|
||||
const finalOpts: child_process.SpawnOptions = {
|
||||
env: { ...process.env },
|
||||
...(opts ?? {}),
|
||||
cwd: dir,
|
||||
stdio: 'inherit',
|
||||
shell: true
|
||||
cwd: path.join(root, dir),
|
||||
shell: true,
|
||||
};
|
||||
|
||||
const command = process.env['npm_command'] || 'install';
|
||||
|
||||
if (process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'] && /^(.build\/distro\/npm\/)?remote$/.test(dir)) {
|
||||
const syncOpts: child_process.SpawnSyncOptions = {
|
||||
env: finalOpts.env,
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
};
|
||||
const userinfo = os.userInfo();
|
||||
log(dir, `Installing dependencies inside container ${process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME']}...`);
|
||||
|
||||
opts.cwd = root;
|
||||
if (process.env['npm_config_arch'] === 'arm64') {
|
||||
run('sudo', ['docker', 'run', '--rm', '--privileged', 'multiarch/qemu-user-static', '--reset', '-p', 'yes'], opts);
|
||||
run('sudo', ['docker', 'run', '--rm', '--privileged', 'multiarch/qemu-user-static', '--reset', '-p', 'yes'], syncOpts);
|
||||
}
|
||||
run('sudo', [
|
||||
'docker', 'run',
|
||||
@@ -63,11 +84,16 @@ function npmInstall(dir: string, opts?: child_process.SpawnSyncOptions) {
|
||||
'-w', path.resolve('/root/vscode', dir),
|
||||
process.env['VSCODE_REMOTE_DEPENDENCIES_CONTAINER_NAME'],
|
||||
'sh', '-c', `\"chown -R root:root ${path.resolve('/root/vscode', dir)} && export PATH="/root/vscode/.build/nodejs-musl/usr/local/bin:$PATH" && npm i -g node-gyp-build && npm ci\"`
|
||||
], opts);
|
||||
run('sudo', ['chown', '-R', `${userinfo.uid}:${userinfo.gid}`, `${path.resolve(root, dir)}`], opts);
|
||||
], syncOpts);
|
||||
run('sudo', ['chown', '-R', `${userinfo.uid}:${userinfo.gid}`, `${path.resolve(root, dir)}`], syncOpts);
|
||||
} else {
|
||||
log(dir, 'Installing dependencies...');
|
||||
run(npm, command.split(' '), opts);
|
||||
const output = await spawnAsync(npm, command.split(' '), finalOpts);
|
||||
if (output.trim()) {
|
||||
for (const line of output.trim().split('\n')) {
|
||||
log(dir, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
removeParcelWatcherPrebuild(dir);
|
||||
}
|
||||
@@ -156,65 +182,115 @@ function clearInheritedNpmrcConfig(dir: string, env: NodeJS.ProcessEnv): void {
|
||||
}
|
||||
}
|
||||
|
||||
for (const dir of dirs) {
|
||||
async function runWithConcurrency(tasks: (() => Promise<void>)[], concurrency: number): Promise<void> {
|
||||
const errors: Error[] = [];
|
||||
let index = 0;
|
||||
|
||||
if (dir === '') {
|
||||
removeParcelWatcherPrebuild(dir);
|
||||
continue; // already executed in root
|
||||
}
|
||||
|
||||
let opts: child_process.SpawnSyncOptions | undefined;
|
||||
|
||||
if (dir === 'build') {
|
||||
opts = {
|
||||
env: {
|
||||
...process.env
|
||||
},
|
||||
};
|
||||
if (process.env['CC']) { opts.env!['CC'] = 'gcc'; }
|
||||
if (process.env['CXX']) { opts.env!['CXX'] = 'g++'; }
|
||||
if (process.env['CXXFLAGS']) { opts.env!['CXXFLAGS'] = ''; }
|
||||
if (process.env['LDFLAGS']) { opts.env!['LDFLAGS'] = ''; }
|
||||
|
||||
setNpmrcConfig('build', opts.env!);
|
||||
npmInstall('build', opts);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/^(.build\/distro\/npm\/)?remote$/.test(dir)) {
|
||||
// node modules used by vscode server
|
||||
opts = {
|
||||
env: {
|
||||
...process.env
|
||||
},
|
||||
};
|
||||
if (process.env['VSCODE_REMOTE_CC']) {
|
||||
opts.env!['CC'] = process.env['VSCODE_REMOTE_CC'];
|
||||
} else {
|
||||
delete opts.env!['CC'];
|
||||
async function worker() {
|
||||
while (index < tasks.length) {
|
||||
const i = index++;
|
||||
try {
|
||||
await tasks[i]();
|
||||
} catch (err) {
|
||||
errors.push(err as Error);
|
||||
}
|
||||
}
|
||||
if (process.env['VSCODE_REMOTE_CXX']) {
|
||||
opts.env!['CXX'] = process.env['VSCODE_REMOTE_CXX'];
|
||||
} else {
|
||||
delete opts.env!['CXX'];
|
||||
}
|
||||
if (process.env['CXXFLAGS']) { delete opts.env!['CXXFLAGS']; }
|
||||
if (process.env['CFLAGS']) { delete opts.env!['CFLAGS']; }
|
||||
if (process.env['LDFLAGS']) { delete opts.env!['LDFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_CXXFLAGS']) { opts.env!['CXXFLAGS'] = process.env['VSCODE_REMOTE_CXXFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_LDFLAGS']) { opts.env!['LDFLAGS'] = process.env['VSCODE_REMOTE_LDFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_NODE_GYP']) { opts.env!['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; }
|
||||
|
||||
setNpmrcConfig('remote', opts.env!);
|
||||
npmInstall(dir, opts);
|
||||
continue;
|
||||
}
|
||||
|
||||
// For directories that don't define their own .npmrc, clear inherited config
|
||||
const env = { ...process.env };
|
||||
clearInheritedNpmrcConfig(dir, env);
|
||||
npmInstall(dir, { env });
|
||||
await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length) }, () => worker()));
|
||||
|
||||
if (errors.length > 0) {
|
||||
for (const err of errors) {
|
||||
console.error(err.message);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
child_process.execSync('git config pull.rebase merges');
|
||||
child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs');
|
||||
async function main() {
|
||||
if (!process.env['VSCODE_FORCE_INSTALL'] && isUpToDate()) {
|
||||
log('.', 'All dependencies up to date, skipping postinstall.');
|
||||
child_process.execSync('git config pull.rebase merges');
|
||||
child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs');
|
||||
return;
|
||||
}
|
||||
|
||||
const _state = computeState();
|
||||
|
||||
const nativeTasks: (() => Promise<void>)[] = [];
|
||||
const parallelTasks: (() => Promise<void>)[] = [];
|
||||
|
||||
for (const dir of dirs) {
|
||||
if (dir === '') {
|
||||
removeParcelWatcherPrebuild(dir);
|
||||
continue; // already executed in root
|
||||
}
|
||||
|
||||
if (dir === 'build') {
|
||||
nativeTasks.push(() => {
|
||||
const env: NodeJS.ProcessEnv = { ...process.env };
|
||||
if (process.env['CC']) { env['CC'] = 'gcc'; }
|
||||
if (process.env['CXX']) { env['CXX'] = 'g++'; }
|
||||
if (process.env['CXXFLAGS']) { env['CXXFLAGS'] = ''; }
|
||||
if (process.env['LDFLAGS']) { env['LDFLAGS'] = ''; }
|
||||
setNpmrcConfig('build', env);
|
||||
return npmInstallAsync('build', { env });
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/^(.build\/distro\/npm\/)?remote$/.test(dir)) {
|
||||
const remoteDir = dir;
|
||||
nativeTasks.push(() => {
|
||||
const env: NodeJS.ProcessEnv = { ...process.env };
|
||||
if (process.env['VSCODE_REMOTE_CC']) {
|
||||
env['CC'] = process.env['VSCODE_REMOTE_CC'];
|
||||
} else {
|
||||
delete env['CC'];
|
||||
}
|
||||
if (process.env['VSCODE_REMOTE_CXX']) {
|
||||
env['CXX'] = process.env['VSCODE_REMOTE_CXX'];
|
||||
} else {
|
||||
delete env['CXX'];
|
||||
}
|
||||
if (process.env['CXXFLAGS']) { delete env['CXXFLAGS']; }
|
||||
if (process.env['CFLAGS']) { delete env['CFLAGS']; }
|
||||
if (process.env['LDFLAGS']) { delete env['LDFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_CXXFLAGS']) { env['CXXFLAGS'] = process.env['VSCODE_REMOTE_CXXFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_LDFLAGS']) { env['LDFLAGS'] = process.env['VSCODE_REMOTE_LDFLAGS']; }
|
||||
if (process.env['VSCODE_REMOTE_NODE_GYP']) { env['npm_config_node_gyp'] = process.env['VSCODE_REMOTE_NODE_GYP']; }
|
||||
setNpmrcConfig('remote', env);
|
||||
return npmInstallAsync(remoteDir, { env });
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const taskDir = dir;
|
||||
parallelTasks.push(() => {
|
||||
const env = { ...process.env };
|
||||
clearInheritedNpmrcConfig(taskDir, env);
|
||||
return npmInstallAsync(taskDir, { env });
|
||||
});
|
||||
}
|
||||
|
||||
// Native dirs (build, remote) run sequentially to avoid node-gyp conflicts
|
||||
for (const task of nativeTasks) {
|
||||
await task();
|
||||
}
|
||||
|
||||
// JS-only dirs run in parallel
|
||||
const concurrency = Math.min(os.cpus().length, 8);
|
||||
log('.', `Running ${parallelTasks.length} npm installs with concurrency ${concurrency}...`);
|
||||
await runWithConcurrency(parallelTasks, concurrency);
|
||||
|
||||
child_process.execSync('git config pull.rebase merges');
|
||||
child_process.execSync('git config blame.ignoreRevsFile .git-blame-ignore-revs');
|
||||
|
||||
fs.writeFileSync(stateFile, JSON.stringify(_state));
|
||||
fs.writeFileSync(stateContentsFile, JSON.stringify(computeContents()));
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as child_process from 'child_process';
|
||||
import * as os from 'os';
|
||||
import { isUpToDate, forceInstallMessage } from './installStateHash.ts';
|
||||
|
||||
if (!process.env['VSCODE_SKIP_NODE_VERSION_CHECK']) {
|
||||
// Get the running Node.js version
|
||||
@@ -41,6 +42,13 @@ if (process.env.npm_execpath?.includes('yarn')) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
// Fast path: if nothing changed since last successful install, skip everything.
|
||||
// This makes `npm i` near-instant when dependencies haven't changed.
|
||||
if (!process.env['VSCODE_FORCE_INSTALL'] && isUpToDate()) {
|
||||
console.log(`\x1b[32mAll dependencies up to date.\x1b[0m ${forceInstallMessage}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
if (!hasSupportedVisualStudioVersion()) {
|
||||
console.error('\x1b[1;31m*** Invalid C/C++ Compiler Toolchain. Please check https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites.\x1b[0;0m');
|
||||
|
||||
Generated
+60
-44
@@ -1027,29 +1027,6 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/balanced-match": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/brace-expansion": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@isaacs/balanced-match": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/cliui": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||
@@ -2170,6 +2147,29 @@
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/vsce/node_modules/balanced-match": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
|
||||
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/vsce/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/vsce/node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -2232,16 +2232,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/vsce/node_modules/glob/node_modules/minimatch": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
|
||||
"integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
|
||||
"version": "10.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
||||
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/brace-expansion": "^5.0.0"
|
||||
"brace-expansion": "^5.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
"node": "18 || 20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
@@ -2318,9 +2318,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz",
|
||||
"integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3493,10 +3493,23 @@
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/fast-xml-builder": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.0.0.tgz",
|
||||
"integrity": "sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz",
|
||||
"integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==",
|
||||
"version": "5.4.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz",
|
||||
"integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3506,6 +3519,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-xml-builder": "^1.0.0",
|
||||
"strnum": "^2.1.2"
|
||||
},
|
||||
"bin": {
|
||||
@@ -4512,9 +4526,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||
"version": "14.1.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz",
|
||||
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4654,10 +4668,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
@@ -6743,12 +6758,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-universal-bundler/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
|
||||
Generated
+113
-111
@@ -8,8 +8,8 @@
|
||||
"name": "@vscode/sample-source",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@vscode/component-explorer": "^0.1.1-12",
|
||||
"@vscode/component-explorer-vite-plugin": "^0.1.1-12",
|
||||
"@vscode/component-explorer": "^0.1.1-19",
|
||||
"@vscode/component-explorer-vite-plugin": "^0.1.1-19",
|
||||
"@vscode/rollup-plugin-esm-url": "^1.0.1-1",
|
||||
"rollup": "*",
|
||||
"vite": "npm:rolldown-vite@latest"
|
||||
@@ -315,9 +315,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz",
|
||||
"integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
||||
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -329,9 +329,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -343,9 +343,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -357,9 +357,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -371,9 +371,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -385,9 +385,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -399,9 +399,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz",
|
||||
"integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -413,9 +413,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz",
|
||||
"integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -427,9 +427,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -441,9 +441,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -455,9 +455,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -469,9 +469,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -483,9 +483,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -497,9 +497,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -511,9 +511,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -525,9 +525,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -539,9 +539,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -553,9 +553,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -567,9 +567,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -581,9 +581,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -595,9 +595,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -609,9 +609,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -623,9 +623,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -637,9 +637,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -651,9 +651,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -683,20 +683,22 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vscode/component-explorer": {
|
||||
"version": "0.1.1-12",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-12.tgz",
|
||||
"integrity": "sha512-qqbxbu3BvqWtwFdVsROLUSd1BiScCiUPP5n0sk0yV1WDATlAl6wQMX1QlmsZy3hag8iP/MXUEj5tSBjA1T7tFw==",
|
||||
"version": "0.1.1-19",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/component-explorer/-/component-explorer-0.1.1-19.tgz",
|
||||
"integrity": "sha512-wvcjw1A8wSH/oR5q+lZrBSyOQZfvXtLPYkQJBj11FBKu35iHko0FTIPMG25Ee+TpT2/BWLd29dWwiJODDQbC8w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vscode/component-explorer-vite-plugin": {
|
||||
"version": "0.1.1-12",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-vite-plugin/-/component-explorer-vite-plugin-0.1.1-12.tgz",
|
||||
"integrity": "sha512-MG5ndoooX2X9PYto1WkNSwWKKmR5OJx3cBnUf7JHm8ERw+8RsZbLe+WS+hVOqnCVPxHy7t+0IYRFl7IC5cuwOQ==",
|
||||
"version": "0.1.1-19",
|
||||
"resolved": "https://registry.npmjs.org/@vscode/component-explorer-vite-plugin/-/component-explorer-vite-plugin-0.1.1-19.tgz",
|
||||
"integrity": "sha512-V0wMhLvHMbeUHOzwGrBPMwwvcbGhXXaQTCGc9hNfF4fjUutOtQFu5o+9XKDG1hIcKgk5qyvcRoXjVazBcg19lA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tinyglobby": "^0.2.0"
|
||||
},
|
||||
@@ -1167,9 +1169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
|
||||
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
|
||||
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1183,31 +1185,31 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.57.1",
|
||||
"@rollup/rollup-android-arm64": "4.57.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.57.1",
|
||||
"@rollup/rollup-darwin-x64": "4.57.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.57.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.57.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.57.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.57.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.57.1",
|
||||
"@rollup/rollup-openbsd-x64": "4.57.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.57.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.57.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.57.1",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.57.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.57.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.59.0",
|
||||
"@rollup/rollup-android-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.59.0",
|
||||
"@rollup/rollup-darwin-x64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.59.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.59.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.59.0",
|
||||
"@rollup/rollup-openbsd-x64": "4.59.0",
|
||||
"@rollup/rollup-openharmony-arm64": "4.59.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.59.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.59.0",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vscode/component-explorer": "^0.1.1-12",
|
||||
"@vscode/component-explorer-vite-plugin": "^0.1.1-12",
|
||||
"@vscode/component-explorer": "^0.1.1-19",
|
||||
"@vscode/component-explorer-vite-plugin": "^0.1.1-19",
|
||||
"@vscode/rollup-plugin-esm-url": "^1.0.1-1",
|
||||
"rollup": "*",
|
||||
"vite": "npm:rolldown-vite@latest"
|
||||
|
||||
@@ -143,11 +143,8 @@ const logger = createLogger();
|
||||
const loggerWarn = logger.warn;
|
||||
|
||||
logger.warn = (msg, options) => {
|
||||
// amdX and the baseUrl code cannot be analyzed by vite.
|
||||
// However, they are not needed, so it is okay to silence the warning.
|
||||
if (msg.indexOf('vs/amdX.ts') !== -1) {
|
||||
return;
|
||||
}
|
||||
// the baseUrl code cannot be analyzed by vite.
|
||||
// However, it is not needed, so it is okay to silence the warning.
|
||||
if (msg.indexOf('await import(new URL(`vs/workbench/workbench.desktop.main.js`, baseUrl).href)') !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
+19
-1
@@ -95,9 +95,12 @@ Name: "runcode"; Description: "{cm:RunAfter,{#NameShort}}"; GroupDescription: "{
|
||||
Name: "{app}"; AfterInstall: DisableAppDirInheritance
|
||||
|
||||
[Files]
|
||||
Source: "*"; Excludes: "\CodeSignSummary*.md,\tools,\tools\*,\policies,\policies\*,\appx,\appx\*,\resources\app\product.json,\{#ExeBasename}.exe,\{#ExeBasename}.VisualElementsManifest.xml,\bin,\bin\*"; DestDir: "{code:GetDestDir}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "*"; Excludes: "\CodeSignSummary*.md,\tools,\tools\*,\policies,\policies\*,\appx,\appx\*,\resources\app\product.json,\{#ExeBasename}.exe,{#ifdef ProxyExeBasename}\{#ProxyExeBasename}.exe,{#endif}\{#ExeBasename}.VisualElementsManifest.xml,\bin,\bin\*"; DestDir: "{code:GetDestDir}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "{#ExeBasename}.exe"; DestDir: "{code:GetDestDir}"; DestName: "{code:GetExeBasename}"; Flags: ignoreversion
|
||||
Source: "{#ExeBasename}.VisualElementsManifest.xml"; DestDir: "{code:GetDestDir}"; DestName: "{code:GetVisualElementsManifest}"; Flags: ignoreversion
|
||||
#ifdef ProxyExeBasename
|
||||
Source: "{#ProxyExeBasename}.exe"; DestDir: "{code:GetDestDir}"; DestName: "{code:GetProxyExeBasename}"; Flags: ignoreversion
|
||||
#endif
|
||||
Source: "tools\*"; DestDir: "{app}\{#VersionedResourcesFolder}\tools"; Flags: ignoreversion
|
||||
Source: "policies\*"; DestDir: "{code:GetDestDir}\{#VersionedResourcesFolder}\policies"; Flags: ignoreversion skipifsourcedoesntexist
|
||||
Source: "bin\{#TunnelApplicationName}.exe"; DestDir: "{code:GetDestDir}\bin"; DestName: "{code:GetBinDirTunnelApplicationFilename}"; Flags: ignoreversion skipifsourcedoesntexist
|
||||
@@ -113,6 +116,11 @@ Source: "appx\{#AppxPackageDll}"; DestDir: "{code:GetDestDir}\{#VersionedResourc
|
||||
Name: "{group}\{#NameLong}"; Filename: "{app}\{#ExeBasename}.exe"; AppUserModelID: "{#AppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{group}\{#NameLong}.lnk'))
|
||||
Name: "{autodesktop}\{#NameLong}"; Filename: "{app}\{#ExeBasename}.exe"; Tasks: desktopicon; AppUserModelID: "{#AppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{autodesktop}\{#NameLong}.lnk'))
|
||||
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#NameLong}"; Filename: "{app}\{#ExeBasename}.exe"; Tasks: quicklaunchicon; AppUserModelID: "{#AppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#NameLong}.lnk'))
|
||||
#ifdef ProxyExeBasename
|
||||
Name: "{group}\{#ProxyExeBasename}"; Filename: "{app}\{#ProxyExeBasename}.exe"; AppUserModelID: "{#ProxyAppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{group}\{#ProxyExeBasename}.lnk'))
|
||||
Name: "{autodesktop}\{#ProxyNameLong}"; Filename: "{app}\{#ProxyExeBasename}.exe"; Tasks: desktopicon; AppUserModelID: "{#ProxyAppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{autodesktop}\{#ProxyNameLong}.lnk'))
|
||||
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#ProxyNameLong}"; Filename: "{app}\{#ProxyExeBasename}.exe"; Tasks: quicklaunchicon; AppUserModelID: "{#ProxyAppUserId}"; Check: ShouldUpdateShortcut(ExpandConstant('{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#ProxyNameLong}.lnk'))
|
||||
#endif
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#ExeBasename}.exe"; Description: "{cm:LaunchProgram,{#NameLong}}"; Tasks: runcode; Flags: nowait postinstall; Check: ShouldRunAfterUpdate
|
||||
@@ -1562,6 +1570,16 @@ begin
|
||||
Result := ExpandConstant('{#ExeBasename}.exe');
|
||||
end;
|
||||
|
||||
#ifdef ProxyExeBasename
|
||||
function GetProxyExeBasename(Value: string): string;
|
||||
begin
|
||||
if IsBackgroundUpdate() and IsVersionedUpdate() then
|
||||
Result := ExpandConstant('new_{#ProxyExeBasename}.exe')
|
||||
else
|
||||
Result := ExpandConstant('{#ProxyExeBasename}.exe');
|
||||
end;
|
||||
#endif
|
||||
|
||||
function GetBinDirTunnelApplicationFilename(Value: string): string;
|
||||
begin
|
||||
if IsBackgroundUpdate() and IsVersionedUpdate() then
|
||||
|
||||
Binary file not shown.
@@ -707,64 +707,6 @@
|
||||
"For more information, please refer to <http://unlicense.org>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@isaacs/balanced-match",
|
||||
"fullLicenseText": [
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright Isaac Z. Schlueter <i@izs.me>",
|
||||
"",
|
||||
"Original code Copyright Julian Gruber <julian@juliangruber.com>",
|
||||
"",
|
||||
"Port to TypeScript Copyright Isaac Z. Schlueter <i@izs.me>",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy of",
|
||||
"this software and associated documentation files (the \"Software\"), to deal in",
|
||||
"the Software without restriction, including without limitation the rights to",
|
||||
"use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies",
|
||||
"of the Software, and to permit persons to whom the Software is furnished to do",
|
||||
"so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all",
|
||||
"copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
|
||||
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
|
||||
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
|
||||
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
|
||||
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE.",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "@isaacs/brace-expansion",
|
||||
"fullLicenseText": [
|
||||
"MIT License",
|
||||
"",
|
||||
"Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>",
|
||||
"",
|
||||
"Permission is hereby granted, free of charge, to any person obtaining a copy",
|
||||
"of this software and associated documentation files (the \"Software\"), to deal",
|
||||
"in the Software without restriction, including without limitation the rights",
|
||||
"to use, copy, modify, merge, publish, distribute, sublicense, and/or sell",
|
||||
"copies of the Software, and to permit persons to whom the Software is",
|
||||
"furnished to do so, subject to the following conditions:",
|
||||
"",
|
||||
"The above copyright notice and this permission notice shall be included in all",
|
||||
"copies or substantial portions of the Software.",
|
||||
"",
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR",
|
||||
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
|
||||
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE",
|
||||
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
|
||||
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,",
|
||||
"OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE",
|
||||
"SOFTWARE.",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
// Reason: License file starts with (MIT) before the copyright, tool can't parse it
|
||||
"name": "balanced-match",
|
||||
|
||||
Generated
+67
-2
@@ -447,6 +447,7 @@ dependencies = [
|
||||
"uuid",
|
||||
"winapi",
|
||||
"winreg 0.50.0",
|
||||
"winresource",
|
||||
"zbus",
|
||||
"zip",
|
||||
]
|
||||
@@ -2645,6 +2646,15 @@ dependencies = [
|
||||
"syn 2.0.115",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -3004,12 +3014,36 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.12+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||
dependencies = [
|
||||
"indexmap 2.13.0",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime 0.7.5+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 0.7.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.15"
|
||||
@@ -3017,10 +3051,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap 2.13.0",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
"toml_datetime 0.6.11",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.9+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
|
||||
dependencies = [
|
||||
"winnow 0.7.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.3"
|
||||
@@ -3699,6 +3748,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.8.0"
|
||||
@@ -3718,6 +3773,16 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winresource"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e287ced0f21cd11f4035fe946fd3af145f068d1acb708afd248100f89ec7432d"
|
||||
dependencies = [
|
||||
"toml",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.51.0"
|
||||
|
||||
@@ -9189,6 +9189,32 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
serde_spanned 1.0.4 - MIT OR Apache-2.0
|
||||
https://github.com/toml-rs/toml
|
||||
|
||||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
serde_urlencoded 0.7.1 - MIT/Apache-2.0
|
||||
https://github.com/nox/serde_urlencoded
|
||||
|
||||
@@ -10517,7 +10543,34 @@ SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
toml 0.9.12+spec-1.1.0 - MIT OR Apache-2.0
|
||||
https://github.com/toml-rs/toml
|
||||
|
||||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
toml_datetime 0.6.11 - MIT OR Apache-2.0
|
||||
toml_datetime 0.7.5+spec-1.1.0 - MIT OR Apache-2.0
|
||||
https://github.com/toml-rs/toml
|
||||
|
||||
../../LICENSE-MIT
|
||||
@@ -10533,6 +10586,58 @@ https://github.com/toml-rs/toml
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
toml_parser 1.0.9+spec-1.1.0 - MIT OR Apache-2.0
|
||||
https://github.com/toml-rs/toml
|
||||
|
||||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
toml_writer 1.0.6+spec-1.1.0 - MIT OR Apache-2.0
|
||||
https://github.com/toml-rs/toml
|
||||
|
||||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
tower-service 0.3.3 - MIT
|
||||
https://github.com/tower-rs/tower
|
||||
|
||||
@@ -12700,6 +12805,7 @@ MIT License
|
||||
---------------------------------------------------------
|
||||
|
||||
winnow 0.5.40 - MIT
|
||||
winnow 0.7.14 - MIT
|
||||
https://github.com/winnow-rs/winnow
|
||||
|
||||
The MIT License (MIT)
|
||||
@@ -12755,6 +12861,40 @@ THE SOFTWARE.
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
winresource 0.1.30 - MIT
|
||||
https://github.com/BenjaminRi/winresource
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2016 Max Resch
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
---------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
wit-bindgen 0.51.0 - Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
|
||||
https://github.com/bytecodealliance/wit-bindgen
|
||||
|
||||
|
||||
+56
-1
@@ -828,6 +828,36 @@ export default tseslint.config(
|
||||
]
|
||||
}
|
||||
},
|
||||
// git extension - ban non-type imports from git.d.ts (use git.constants for runtime values)
|
||||
{
|
||||
files: [
|
||||
'extensions/git/src/**/*.ts',
|
||||
],
|
||||
ignores: [
|
||||
'extensions/git/src/api/git.constants.ts',
|
||||
],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': tseslint.plugin,
|
||||
},
|
||||
rules: {
|
||||
'no-restricted-imports': 'off',
|
||||
'@typescript-eslint/no-restricted-imports': [
|
||||
'warn',
|
||||
{
|
||||
'patterns': [
|
||||
{
|
||||
'group': ['*/api/git'],
|
||||
'allowTypeImports': true,
|
||||
'message': 'Use \'import type\' for types from git.d.ts and import runtime const enum values from git.constants instead'
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// vscode API
|
||||
{
|
||||
files: [
|
||||
@@ -1955,7 +1985,8 @@ export default tseslint.config(
|
||||
'vs/workbench/browser/**',
|
||||
'vs/workbench/contrib/**',
|
||||
'vs/workbench/services/*/~',
|
||||
'vs/sessions/~'
|
||||
'vs/sessions/~',
|
||||
'vs/sessions/services/*/~'
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1974,6 +2005,30 @@ export default tseslint.config(
|
||||
'vs/sessions/contrib/*/~'
|
||||
]
|
||||
},
|
||||
{
|
||||
'target': 'src/vs/sessions/services/*/~',
|
||||
'restrictions': [
|
||||
'vs/base/~',
|
||||
'vs/base/parts/*/~',
|
||||
'vs/platform/*/~',
|
||||
'vs/editor/~',
|
||||
'vs/editor/contrib/*/~',
|
||||
'vs/workbench/~',
|
||||
'vs/workbench/services/*/~',
|
||||
{
|
||||
'when': 'test',
|
||||
'pattern': 'vs/workbench/contrib/*/~'
|
||||
}, // TODO@layers
|
||||
'tas-client', // node module allowed even in /common/
|
||||
'vscode-textmate', // node module allowed even in /common/
|
||||
'@vscode/vscode-languagedetection', // node module allowed even in /common/
|
||||
'@vscode/tree-sitter-wasm', // type import
|
||||
{
|
||||
'when': 'hasBrowser',
|
||||
'pattern': '@xterm/xterm'
|
||||
} // node module allowed even in /browser/
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Contributing to Built-In Extensions
|
||||
|
||||
This directory contains built-in extensions that ship with VS Code.
|
||||
|
||||
## Basic Structure
|
||||
|
||||
A typical TypeScript-based built-in extension has the following structure:
|
||||
|
||||
- `package.json`: extension manifest.
|
||||
- `src/`: Main directory for TypeScript source code.
|
||||
- `tsconfig.json`: primary TypeScript config. This should inherit from `tsconfig.base.json`.
|
||||
- `esbuild.mts`: esbuild build script used for production builds.
|
||||
- `.vscodeignore`: Ignore file list. You can copy this from an existing extension.
|
||||
|
||||
TypeScript-based extensions have the following output structure:
|
||||
|
||||
- `out`: Output directory for development builds
|
||||
- `dist`: Output directory for production builds.
|
||||
|
||||
|
||||
## Enabling an Extension in the Browser
|
||||
|
||||
By default extensions will only target desktop. To enable an extension in browsers as well:
|
||||
|
||||
- Add a `"browser"` entry in `package.json` pointing to the browser bundle (for example `"./dist/browser/extension"`).
|
||||
- Add `tsconfig.browser.json` that typechecks only browser-safe sources.
|
||||
- Add an `esbuild.browser.mts` file. This should set `platform: 'browser'`.
|
||||
|
||||
Make sure the browser build of the extension only uses browser-safe APIs. If an extension needs different behavior between desktop and web, you can create distinct entrypoints for each target:
|
||||
|
||||
- `src/extension.ts`: Desktop entrypoint.
|
||||
- `src/extension.browser.ts`: Browser entrypoint. Make sure `esbuild.browser.mts` builds this and that `tsconfig.browser.json` targets it.
|
||||
+3
-3
@@ -51,9 +51,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz",
|
||||
"integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==",
|
||||
"version": "10.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz",
|
||||
"integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^5.0.2"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"git": {
|
||||
"name": "microsoft/vscode-css",
|
||||
"repositoryUrl": "https://github.com/microsoft/vscode-css",
|
||||
"commitHash": "a927fe2f73927bf5c25d0b0c4dd0e63d69fd8887"
|
||||
"commitHash": "9a07d76cb0e7a56f9bfc76328a57227751e4adb4"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/microsoft/vscode-css/commit/a927fe2f73927bf5c25d0b0c4dd0e63d69fd8887",
|
||||
"version": "https://github.com/microsoft/vscode-css/commit/9a07d76cb0e7a56f9bfc76328a57227751e4adb4",
|
||||
"name": "CSS",
|
||||
"scopeName": "source.css",
|
||||
"patterns": [
|
||||
@@ -1401,7 +1401,7 @@
|
||||
"property-keywords": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?xi) (?<![\\w-])\n(above|absolute|active|add|additive|after-edge|alias|all|all-petite-caps|all-scroll|all-small-caps|alpha|alphabetic|alternate|alternate-reverse\n|always|antialiased|auto|auto-fill|auto-fit|auto-pos|available|avoid|avoid-column|avoid-page|avoid-region|backwards|balance|baseline|before-edge|below|bevel\n|bidi-override|blink|block|block-axis|block-start|block-end|bold|bolder|border|border-box|both|bottom|bottom-outside|break-all|break-word|bullets\n|butt|capitalize|caption|cell|center|central|char|circle|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color|color-burn\n|color-dodge|column|column-reverse|common-ligatures|compact|condensed|contain|content|content-box|contents|context-menu|contextual|copy|cover\n|crisp-edges|crispEdges|crosshair|cyclic|dark|darken|dashed|decimal|default|dense|diagonal-fractions|difference|digits|disabled|disc|discretionary-ligatures\n|distribute|distribute-all-lines|distribute-letter|distribute-space|dot|dotted|double|double-circle|downleft|downright|e-resize|each-line|ease|ease-in\n|ease-in-out|ease-out|economy|ellipse|ellipsis|embed|end|evenodd|ew-resize|exact|exclude|exclusion|expanded|extends|extra-condensed|extra-expanded\n|fallback|farthest-corner|farthest-side|fill|fill-available|fill-box|filled|fit-content|fixed|flat|flex|flex-end|flex-start|flip|flow-root|forwards|freeze\n|from-image|full-width|geometricPrecision|georgian|grab|grabbing|grayscale|grid|groove|hand|hanging|hard-light|help|hidden|hide\n|historical-forms|historical-ligatures|horizontal|horizontal-tb|hue|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space\n|ideographic|inactive|infinite|inherit|initial|inline|inline-axis|inline-block|inline-end|inline-flex|inline-grid|inline-list-item|inline-start\n|inline-table|inset|inside|inter-character|inter-ideograph|inter-word|intersect|invert|isolate|isolate-override|italic|jis04|jis78|jis83\n|jis90|justify|justify-all|kannada|keep-all|landscape|large|larger|left|light|lighten|lighter|line|line-edge|line-through|linear|linearRGB\n|lining-nums|list-item|local|loose|lowercase|lr|lr-tb|ltr|luminance|luminosity|main-size|mandatory|manipulation|manual|margin-box|match-parent\n|match-source|mathematical|max-content|medium|menu|message-box|middle|min-content|miter|mixed|move|multiply|n-resize|narrower|ne-resize\n|nearest-neighbor|nesw-resize|newspaper|no-change|no-clip|no-close-quote|no-common-ligatures|no-contextual|no-discretionary-ligatures\n|no-drop|no-historical-ligatures|no-open-quote|no-repeat|none|nonzero|normal|not-allowed|nowrap|ns-resize|numbers|numeric|nw-resize|nwse-resize\n|oblique|oldstyle-nums|open|open-quote|optimizeLegibility|optimizeQuality|optimizeSpeed|optional|ordinal|outset|outside|over|overlay|overline|padding\n|padding-box|page|painted|pan-down|pan-left|pan-right|pan-up|pan-x|pan-y|paused|petite-caps|pixelated|plaintext|pointer|portrait|pre|pre-line\n|pre-wrap|preserve-3d|progress|progressive|proportional-nums|proportional-width|proximity|radial|recto|region|relative|remove|repeat|repeat-[xy]\n|reset-size|reverse|revert|ridge|right|rl|rl-tb|round|row|row-resize|row-reverse|row-severse|rtl|ruby|ruby-base|ruby-base-container|ruby-text\n|ruby-text-container|run-in|running|s-resize|saturation|scale-down|screen|scroll|scroll-position|se-resize|semi-condensed|semi-expanded|separate\n|sesame|show|sideways|sideways-left|sideways-lr|sideways-right|sideways-rl|simplified|slashed-zero|slice|small|small-caps|small-caption|smaller\n|smooth|soft-light|solid|space|space-around|space-between|space-evenly|spell-out|square|sRGB|stacked-fractions|start|static|status-bar|swap\n|step-end|step-start|sticky|stretch|strict|stroke|stroke-box|style|sub|subgrid|subpixel-antialiased|subtract|super|sw-resize|symbolic|table\n|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row|table-row-group|tabular-nums|tb|tb-rl\n|text|text-after-edge|text-before-edge|text-bottom|text-top|thick|thin|titling-caps|top|top-outside|touch|traditional|transparent|triangle\n|ultra-condensed|ultra-expanded|under|underline|unicase|unset|upleft|uppercase|upright|use-glyph-orientation|use-script|verso|vertical\n|vertical-ideographic|vertical-lr|vertical-rl|vertical-text|view-box|visible|visibleFill|visiblePainted|visibleStroke|w-resize|wait|wavy\n|weight|whitespace|wider|words|wrap|wrap-reverse|x|x-large|x-small|xx-large|xx-small|y|zero|zoom-in|zoom-out)\n(?![\\w-])",
|
||||
"match": "(?xi) (?<![\\w-])\n(above|absolute|active|add|additive|after-edge|alias|all|all-petite-caps|all-scroll|all-small-caps|alpha|alphabetic|alternate|alternate-reverse\n|always|antialiased|auto|auto-fill|auto-fit|auto-pos|available|avoid|avoid-column|avoid-page|avoid-region|backwards|balance|baseline|before-edge|below|bevel\n|bidi-override|blink|block|block-axis|block-start|block-end|bold|bolder|border|border-box|both|bottom|bottom-outside|break-all|break-word|bullets\n|butt|capitalize|caption|cell|center|central|char|circle|clip|clone|close-quote|closest-corner|closest-side|col-resize|collapse|color|color-burn\n|color-dodge|column|column-reverse|common-ligatures|compact|condensed|contain|content|content-box|contents|context-menu|contextual|copy|cover\n|crisp-edges|crispEdges|crosshair|cyclic|dark|darken|dashed|decimal|default|dense|diagonal-fractions|difference|digits|disabled|disc|discretionary-ligatures\n|distribute|distribute-all-lines|distribute-letter|distribute-space|dot|dotted|double|double-circle|downleft|downright|e-resize|each-line|ease|ease-in\n|ease-in-out|ease-out|economy|ellipse|ellipsis|embed|end|evenodd|ew-resize|exact|exclude|exclusion|expanded|extends|extra-condensed|extra-expanded\n|fallback|farthest-corner|farthest-side|fill|fill-available|fill-box|filled|fit-content|fixed|flat|flex|flex-end|flex-start|flip|flow|flow-root|forwards|freeze\n|from-image|full-width|geometricPrecision|georgian|grab|grabbing|grayscale|grid|groove|hand|hanging|hard-light|help|hidden|hide\n|historical-forms|historical-ligatures|horizontal|horizontal-tb|hue|icon|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space\n|ideographic|inactive|infinite|inherit|initial|inline|inline-axis|inline-block|inline-end|inline-flex|inline-grid|inline-list-item|inline-start\n|inline-table|inset|inside|inter-character|inter-ideograph|inter-word|intersect|invert|isolate|isolate-override|italic|jis04|jis78|jis83\n|jis90|justify|justify-all|kannada|keep-all|landscape|large|larger|left|light|lighten|lighter|line|line-edge|line-through|linear|linearRGB\n|lining-nums|list-item|local|loose|lowercase|lr|lr-tb|ltr|luminance|luminosity|main-size|mandatory|manipulation|manual|margin-box|match-parent\n|match-source|mathematical|max-content|medium|menu|message-box|middle|min-content|miter|mixed|move|multiply|n-resize|narrower|ne-resize\n|nearest-neighbor|nesw-resize|newspaper|no-change|no-clip|no-close-quote|no-common-ligatures|no-contextual|no-discretionary-ligatures\n|no-drop|no-historical-ligatures|no-open-quote|no-repeat|none|nonzero|normal|not-allowed|nowrap|ns-resize|numbers|numeric|nw-resize|nwse-resize\n|oblique|oldstyle-nums|open|open-quote|optimizeLegibility|optimizeQuality|optimizeSpeed|optional|ordinal|outset|outside|over|overlay|overline|padding\n|padding-box|page|painted|pan-down|pan-left|pan-right|pan-up|pan-x|pan-y|paused|petite-caps|pixelated|plaintext|pointer|portrait|pre|pre-line\n|pre-wrap|preserve-3d|progress|progressive|proportional-nums|proportional-width|proximity|radial|recto|region|relative|remove|repeat|repeat-[xy]\n|reset-size|reverse|revert|revert-layer|ridge|right|rl|rl-tb|round|row|row-resize|row-reverse|row-severse|rtl|ruby|ruby-base|ruby-base-container|ruby-text\n|ruby-text-container|run-in|running|s-resize|saturation|scale-down|screen|scroll|scroll-position|se-resize|semi-condensed|semi-expanded|separate\n|sesame|show|sideways|sideways-left|sideways-lr|sideways-right|sideways-rl|simplified|slashed-zero|slice|small|small-caps|small-caption|smaller\n|smooth|soft-light|solid|space|space-around|space-between|space-evenly|spell-out|square|sRGB|stacked-fractions|start|static|status-bar|swap\n|step-end|step-start|sticky|stretch|strict|stroke|stroke-box|style|sub|subgrid|subpixel-antialiased|subtract|super|sw-resize|symbolic|table\n|table-caption|table-cell|table-column|table-column-group|table-footer-group|table-header-group|table-row|table-row-group|tabular-nums|tb|tb-rl\n|text|text-after-edge|text-before-edge|text-bottom|text-top|thick|thin|titling-caps|top|top-outside|touch|traditional|transparent|triangle\n|ultra-condensed|ultra-expanded|under|underline|unicase|unset|upleft|uppercase|upright|use-glyph-orientation|use-script|verso|vertical\n|vertical-ideographic|vertical-lr|vertical-rl|vertical-text|view-box|visible|visibleFill|visiblePainted|visibleStroke|w-resize|wait|wavy\n|weight|whitespace|wider|words|wrap|wrap-reverse|x|x-large|x-small|xx-large|xx-small|y|zero|zoom-in|zoom-out)\n(?![\\w-])",
|
||||
"name": "support.constant.property-value.css"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"git": {
|
||||
"name": "dart-lang/dart-syntax-highlight",
|
||||
"repositoryUrl": "https://github.com/dart-lang/dart-syntax-highlight",
|
||||
"commitHash": "e1ac5c446c2531343393adbe8fff9d45d8a7c412"
|
||||
"commitHash": "b2e04fbe2334bfe56940106b652f4c5799affbb1"
|
||||
}
|
||||
},
|
||||
"licenseDetail": [
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
|
||||
"Once accepted there, we are happy to receive an update request."
|
||||
],
|
||||
"version": "https://github.com/dart-lang/dart-syntax-highlight/commit/e1ac5c446c2531343393adbe8fff9d45d8a7c412",
|
||||
"version": "https://github.com/dart-lang/dart-syntax-highlight/commit/b2e04fbe2334bfe56940106b652f4c5799affbb1",
|
||||
"name": "Dart",
|
||||
"scopeName": "source.dart",
|
||||
"patterns": [
|
||||
@@ -58,6 +58,12 @@
|
||||
{
|
||||
"include": "#constants-and-special-vars"
|
||||
},
|
||||
{
|
||||
"include": "#class-identifier-with-optional-factory-method"
|
||||
},
|
||||
{
|
||||
"include": "#function-identifier"
|
||||
},
|
||||
{
|
||||
"include": "#operators"
|
||||
},
|
||||
@@ -224,12 +230,49 @@
|
||||
{
|
||||
"name": "constant.numeric.dart",
|
||||
"match": "(?<!\\$)\\b((0(x|X)[0-9a-fA-F][0-9a-fA-F_]*)|(([0-9][0-9_]*\\.?[0-9_]*)|(\\.[0-9][0-9_]*))((e|E)(\\+|-)?[0-9][0-9_]*)?)\\b(?!\\$)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"class-identifier-with-optional-factory-method": {
|
||||
"patterns": [
|
||||
{
|
||||
"match": "(?<!\\$)\\b(bool|num|int|double|dynamic)\\b(?!\\$)\\s*(factory\\b)?",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "support.class.dart"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.function.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#class-identifier"
|
||||
"match": "(?<!\\$)\\b(void)\\b(?!\\$)\\s*(factory\\b)?",
|
||||
"captures": {
|
||||
"1": {
|
||||
"name": "storage.type.primitive.dart"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.function.dart"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"include": "#function-identifier"
|
||||
"begin": "(?<![a-zA-Z0-9_$])([_$]*[A-Z][a-zA-Z0-9_$]*)\\b\\s*(factory\\b)?",
|
||||
"end": "(?!<)",
|
||||
"beginCaptures": {
|
||||
"1": {
|
||||
"name": "support.class.dart"
|
||||
},
|
||||
"2": {
|
||||
"name": "entity.name.function.dart"
|
||||
}
|
||||
},
|
||||
"patterns": [
|
||||
{
|
||||
"include": "#type-args"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -275,6 +318,10 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": "(?<=\\.)new\\b",
|
||||
"name": "entity.name.function.dart"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -330,8 +377,8 @@
|
||||
"match": "(?<!\\$)\\bassert\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.new.dart",
|
||||
"match": "(?<!\\$)\\b(new)\\b(?!\\$)"
|
||||
"name": "keyword.new.dart",
|
||||
"match": "(?<![\\$\\.])\\b(new)\\b(?!\\$)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.control.return.dart",
|
||||
@@ -347,7 +394,7 @@
|
||||
},
|
||||
{
|
||||
"name": "storage.type.primitive.dart",
|
||||
"match": "(?<!\\$)\\b(?:void|var)\\b(?!\\$)"
|
||||
"match": "(?<!\\$)\\b(?:var)\\b(?!\\$)"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -404,6 +451,12 @@
|
||||
{
|
||||
"include": "#constants-and-special-vars"
|
||||
},
|
||||
{
|
||||
"include": "#class-identifier-with-optional-factory-method"
|
||||
},
|
||||
{
|
||||
"include": "#function-identifier"
|
||||
},
|
||||
{
|
||||
"include": "#strings"
|
||||
},
|
||||
|
||||
@@ -15,4 +15,7 @@ run({
|
||||
},
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
additionalOptions: {
|
||||
tsconfig: path.join(import.meta.dirname, 'tsconfig.browser.json'),
|
||||
},
|
||||
}, process.argv);
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { PackageDocument } from './packageDocumentHelper';
|
||||
import { PackageDocumentL10nSupport } from './packageDocumentL10nSupport';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
//package.json suggestions
|
||||
context.subscriptions.push(registerPackageDocumentCompletions());
|
||||
|
||||
//package.json go to definition for NLS strings
|
||||
context.subscriptions.push(new PackageDocumentL10nSupport());
|
||||
}
|
||||
|
||||
function registerPackageDocumentCompletions(): vscode.Disposable {
|
||||
@@ -18,5 +21,4 @@ function registerPackageDocumentCompletions(): vscode.Disposable {
|
||||
return new PackageDocument(document).provideCompletionItems(position, token);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { PackageDocument } from './packageDocumentHelper';
|
||||
import { PackageDocumentL10nSupport } from './packageDocumentL10nSupport';
|
||||
import { ExtensionLinter } from './extensionLinter';
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
@@ -15,6 +16,9 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
//package.json code actions for lint warnings
|
||||
context.subscriptions.push(registerCodeActionsProvider());
|
||||
|
||||
// package.json l10n support
|
||||
context.subscriptions.push(new PackageDocumentL10nSupport());
|
||||
|
||||
context.subscriptions.push(new ExtensionLinter());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { getLocation, getNodeValue, parseTree, findNodeAtLocation, visit } from 'jsonc-parser';
|
||||
|
||||
|
||||
const packageJsonSelector: vscode.DocumentSelector = { language: 'json', pattern: '**/package.json' };
|
||||
const packageNlsJsonSelector: vscode.DocumentSelector = { language: 'json', pattern: '**/package.nls.json' };
|
||||
|
||||
export class PackageDocumentL10nSupport implements vscode.DefinitionProvider, vscode.ReferenceProvider, vscode.Disposable {
|
||||
|
||||
private readonly _disposables: vscode.Disposable[] = [];
|
||||
|
||||
constructor() {
|
||||
this._disposables.push(vscode.languages.registerDefinitionProvider(packageJsonSelector, this));
|
||||
this._disposables.push(vscode.languages.registerDefinitionProvider(packageNlsJsonSelector, this));
|
||||
|
||||
this._disposables.push(vscode.languages.registerReferenceProvider(packageNlsJsonSelector, this));
|
||||
this._disposables.push(vscode.languages.registerReferenceProvider(packageJsonSelector, this));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const d of this._disposables) {
|
||||
d.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async provideDefinition(document: vscode.TextDocument, position: vscode.Position, _token: vscode.CancellationToken): Promise<vscode.DefinitionLink[] | undefined> {
|
||||
const basename = document.uri.path.split('/').pop()?.toLowerCase();
|
||||
if (basename === 'package.json') {
|
||||
return this.provideNlsValueDefinition(document, position);
|
||||
}
|
||||
|
||||
if (basename === 'package.nls.json') {
|
||||
return this.provideNlsKeyDefinition(document, position);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async provideNlsValueDefinition(packageJsonDoc: vscode.TextDocument, position: vscode.Position): Promise<vscode.DefinitionLink[] | undefined> {
|
||||
const nlsRef = this.getNlsReferenceAtPosition(packageJsonDoc, position);
|
||||
if (!nlsRef) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nlsUri = vscode.Uri.joinPath(packageJsonDoc.uri, '..', 'package.nls.json');
|
||||
return this.resolveNlsDefinition(nlsRef, nlsUri);
|
||||
}
|
||||
|
||||
private async provideNlsKeyDefinition(nlsDoc: vscode.TextDocument, position: vscode.Position): Promise<vscode.DefinitionLink[] | undefined> {
|
||||
const nlsKey = this.getNlsKeyDefinitionAtPosition(nlsDoc, position);
|
||||
if (!nlsKey) {
|
||||
return undefined;
|
||||
}
|
||||
return this.resolveNlsDefinition(nlsKey, nlsDoc.uri);
|
||||
}
|
||||
|
||||
private async resolveNlsDefinition(origin: { key: string; range: vscode.Range }, nlsUri: vscode.Uri): Promise<vscode.DefinitionLink[] | undefined> {
|
||||
const target = await this.findNlsKeyDeclaration(origin.key, nlsUri);
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return [{
|
||||
originSelectionRange: origin.range,
|
||||
targetUri: target.uri,
|
||||
targetRange: target.range,
|
||||
}];
|
||||
}
|
||||
|
||||
private getNlsReferenceAtPosition(packageJsonDoc: vscode.TextDocument, position: vscode.Position): { key: string; range: vscode.Range } | undefined {
|
||||
const location = getLocation(packageJsonDoc.getText(), packageJsonDoc.offsetAt(position));
|
||||
if (!location.previousNode || location.previousNode.type !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const value = getNodeValue(location.previousNode);
|
||||
if (typeof value !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const match = value.match(/^%(.+)%$/);
|
||||
if (!match) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nodeStart = packageJsonDoc.positionAt(location.previousNode.offset);
|
||||
const nodeEnd = packageJsonDoc.positionAt(location.previousNode.offset + location.previousNode.length);
|
||||
return { key: match[1], range: new vscode.Range(nodeStart, nodeEnd) };
|
||||
}
|
||||
|
||||
public async provideReferences(document: vscode.TextDocument, position: vscode.Position, context: vscode.ReferenceContext, _token: vscode.CancellationToken): Promise<vscode.Location[] | undefined> {
|
||||
const basename = document.uri.path.split('/').pop()?.toLowerCase();
|
||||
if (basename === 'package.nls.json') {
|
||||
return this.provideNlsKeyReferences(document, position, context);
|
||||
}
|
||||
if (basename === 'package.json') {
|
||||
return this.provideNlsValueReferences(document, position, context);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async provideNlsKeyReferences(nlsDoc: vscode.TextDocument, position: vscode.Position, context: vscode.ReferenceContext): Promise<vscode.Location[] | undefined> {
|
||||
const nlsKey = this.getNlsKeyDefinitionAtPosition(nlsDoc, position);
|
||||
if (!nlsKey) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const packageJsonUri = vscode.Uri.joinPath(nlsDoc.uri, '..', 'package.json');
|
||||
return this.findAllNlsReferences(nlsKey.key, packageJsonUri, nlsDoc.uri, context);
|
||||
}
|
||||
|
||||
private async provideNlsValueReferences(packageJsonDoc: vscode.TextDocument, position: vscode.Position, context: vscode.ReferenceContext): Promise<vscode.Location[] | undefined> {
|
||||
const nlsRef = this.getNlsReferenceAtPosition(packageJsonDoc, position);
|
||||
if (!nlsRef) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nlsUri = vscode.Uri.joinPath(packageJsonDoc.uri, '..', 'package.nls.json');
|
||||
return this.findAllNlsReferences(nlsRef.key, packageJsonDoc.uri, nlsUri, context);
|
||||
}
|
||||
|
||||
private async findAllNlsReferences(nlsKey: string, packageJsonUri: vscode.Uri, nlsUri: vscode.Uri, context: vscode.ReferenceContext): Promise<vscode.Location[]> {
|
||||
const locations = await this.findNlsReferencesInPackageJson(nlsKey, packageJsonUri);
|
||||
|
||||
if (context.includeDeclaration) {
|
||||
const decl = await this.findNlsKeyDeclaration(nlsKey, nlsUri);
|
||||
if (decl) {
|
||||
locations.push(decl);
|
||||
}
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
private async findNlsKeyDeclaration(nlsKey: string, nlsUri: vscode.Uri): Promise<vscode.Location | undefined> {
|
||||
try {
|
||||
const nlsDoc = await vscode.workspace.openTextDocument(nlsUri);
|
||||
const nlsTree = parseTree(nlsDoc.getText());
|
||||
if (!nlsTree) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const node = findNodeAtLocation(nlsTree, [nlsKey]);
|
||||
if (!node?.parent) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const keyNode = node.parent.children?.[0];
|
||||
if (!keyNode) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const start = nlsDoc.positionAt(keyNode.offset);
|
||||
const end = nlsDoc.positionAt(keyNode.offset + keyNode.length);
|
||||
return new vscode.Location(nlsUri, new vscode.Range(start, end));
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async findNlsReferencesInPackageJson(nlsKey: string, packageJsonUri: vscode.Uri): Promise<vscode.Location[]> {
|
||||
let packageJsonDoc: vscode.TextDocument;
|
||||
try {
|
||||
packageJsonDoc = await vscode.workspace.openTextDocument(packageJsonUri);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
const text = packageJsonDoc.getText();
|
||||
const needle = `%${nlsKey}%`;
|
||||
const locations: vscode.Location[] = [];
|
||||
|
||||
visit(text, {
|
||||
onLiteralValue(value, offset, length) {
|
||||
if (value === needle) {
|
||||
const start = packageJsonDoc.positionAt(offset);
|
||||
const end = packageJsonDoc.positionAt(offset + length);
|
||||
locations.push(new vscode.Location(packageJsonUri, new vscode.Range(start, end)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
private getNlsKeyDefinitionAtPosition(nlsDoc: vscode.TextDocument, position: vscode.Position): { key: string; range: vscode.Range } | undefined {
|
||||
const location = getLocation(nlsDoc.getText(), nlsDoc.offsetAt(position));
|
||||
|
||||
// Must be on a top-level property key
|
||||
if (location.path.length !== 1 || !location.isAtPropertyKey || !location.previousNode) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const key = location.path[0] as string;
|
||||
const start = nlsDoc.positionAt(location.previousNode.offset);
|
||||
const end = nlsDoc.positionAt(location.previousNode.offset + location.previousNode.length);
|
||||
return { key, range: new vscode.Range(start, end) };
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,5 @@ test/**
|
||||
out/**
|
||||
tsconfig*.json
|
||||
build/**
|
||||
extension.webpack.config.js
|
||||
esbuild*.mts
|
||||
package-lock.json
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as path from 'node:path';
|
||||
import { run } from '../esbuild-extension-common.mts';
|
||||
|
||||
const srcDir = path.join(import.meta.dirname, 'src');
|
||||
const outDir = path.join(import.meta.dirname, 'dist');
|
||||
|
||||
run({
|
||||
platform: 'node',
|
||||
entryPoints: {
|
||||
'main': path.join(srcDir, 'main.ts'),
|
||||
'askpass-main': path.join(srcDir, 'askpass-main.ts'),
|
||||
'git-editor-main': path.join(srcDir, 'git-editor-main.ts'),
|
||||
},
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
@@ -1147,6 +1147,46 @@
|
||||
"title": "%command.deleteRef%",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyBranchName",
|
||||
"title": "%command.artifactCopyBranchName%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyCommitHash",
|
||||
"title": "%command.artifactCopyCommitHash%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyPath",
|
||||
"title": "%command.artifactCopyWorktreePath%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyCommitHash",
|
||||
"title": "%command.artifactCopyCommitHash%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyBranchName",
|
||||
"title": "%command.artifactCopyBranchName%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyTagName",
|
||||
"title": "%command.artifactCopyTagName%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyStashName",
|
||||
"title": "%command.artifactCopyStashName%",
|
||||
"category": "Git"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.stashCopyBranchName",
|
||||
"title": "%command.artifactCopyBranchName%",
|
||||
"category": "Git"
|
||||
}
|
||||
],
|
||||
"continueEditSession": [
|
||||
@@ -1846,6 +1886,38 @@
|
||||
{
|
||||
"command": "git.repositories.deleteWorktree",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyBranchName",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyCommitHash",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyPath",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyCommitHash",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyBranchName",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyTagName",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyStashName",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.stashCopyBranchName",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"scm/title": [
|
||||
@@ -2090,6 +2162,16 @@
|
||||
"group": "3_drop@3",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == stashes"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.stashCopyBranchName",
|
||||
"group": "4_copy@1",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == stashes"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyStashName",
|
||||
"group": "4_copy@2",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == stashes"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.checkout",
|
||||
"group": "1_checkout@1",
|
||||
@@ -2130,6 +2212,21 @@
|
||||
"group": "4_compare@1",
|
||||
"when": "scmProvider == git && (scmArtifactGroupId == branches || scmArtifactGroupId == tags)"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyCommitHash",
|
||||
"group": "5_copy@2",
|
||||
"when": "scmProvider == git && (scmArtifactGroupId == branches || scmArtifactGroupId == tags)"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyBranchName",
|
||||
"group": "5_copy@1",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == branches"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.copyTagName",
|
||||
"group": "5_copy@2",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == tags"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.openWorktreeInNewWindow",
|
||||
"group": "inline@1",
|
||||
@@ -2149,6 +2246,21 @@
|
||||
"command": "git.repositories.deleteWorktree",
|
||||
"group": "2_modify@1",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == worktrees"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyCommitHash",
|
||||
"group": "3_copy@2",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == worktrees"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyBranchName",
|
||||
"group": "3_copy@1",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == worktrees"
|
||||
},
|
||||
{
|
||||
"command": "git.repositories.worktreeCopyPath",
|
||||
"group": "3_copy@3",
|
||||
"when": "scmProvider == git && scmArtifactGroupId == worktrees"
|
||||
}
|
||||
],
|
||||
"scm/resourceGroup/context": [
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
"command.stashView": "View Stash...",
|
||||
"command.stashView2": "View Stash",
|
||||
"command.timelineOpenDiff": "Open Changes",
|
||||
"command.timelineCopyCommitId": "Copy Commit ID",
|
||||
"command.timelineCopyCommitId": "Copy Commit Hash",
|
||||
"command.timelineCopyCommitMessage": "Copy Commit Message",
|
||||
"command.timelineSelectForCompare": "Select for Compare",
|
||||
"command.timelineCompareWithSelected": "Compare with Selected",
|
||||
@@ -148,6 +148,11 @@
|
||||
"command.graphCompareWithMergeBase": "Compare with Merge Base",
|
||||
"command.graphCompareWithRemote": "Compare with Remote",
|
||||
"command.deleteRef": "Delete",
|
||||
"command.artifactCopyCommitHash": "Copy Commit Hash",
|
||||
"command.artifactCopyBranchName": "Copy Branch Name",
|
||||
"command.artifactCopyTagName": "Copy Tag Name",
|
||||
"command.artifactCopyStashName": "Copy Stash Name",
|
||||
"command.artifactCopyWorktreePath": "Copy Worktree Path",
|
||||
"command.blameToggleEditorDecoration": "Toggle Git Blame Editor Decoration",
|
||||
"command.blameToggleStatusBarItem": "Toggle Git Blame Status Bar Item",
|
||||
"command.api.getRepositories": "Get Repositories",
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Command, Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace, l10n, LogOutputChannel } from 'vscode';
|
||||
import { Branch, RefType, Status } from './api/git';
|
||||
import type { Branch } from './api/git';
|
||||
import { RefType, Status } from './api/git.constants';
|
||||
import { OperationKind } from './operation';
|
||||
import { CommitCommandsCenter } from './postCommitCommands';
|
||||
import { Repository } from './repository';
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
import { Model } from '../model';
|
||||
import { Repository as BaseRepository, Resource } from '../repository';
|
||||
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider, GitErrorCodes, CloneOptions, CommitShortStat, DiffChange, Worktree, RepositoryKind, RepositoryAccessDetails } from './git';
|
||||
import type { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, LogOptions, APIState, CommitOptions, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider, CloneOptions, CommitShortStat, DiffChange, Worktree, RepositoryKind, RepositoryAccessDetails } from './git';
|
||||
import { ForcePushMode, GitErrorCodes, RefType, Status } from './git.constants';
|
||||
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode';
|
||||
import { combinedDisposable, filterEvent, mapEvent } from '../util';
|
||||
import { toGitUri } from '../uri';
|
||||
@@ -319,6 +320,10 @@ export class ApiRepository implements Repository {
|
||||
return this.#repository.mergeAbort();
|
||||
}
|
||||
|
||||
rebase(branch: string): Promise<void> {
|
||||
return this.#repository.rebase(branch);
|
||||
}
|
||||
|
||||
createStash(options?: { message?: string; includeUntracked?: boolean; staged?: boolean }): Promise<void> {
|
||||
return this.#repository.createStash(options?.message, options?.includeUntracked, options?.staged);
|
||||
}
|
||||
@@ -346,6 +351,10 @@ export class ApiRepository implements Repository {
|
||||
migrateChanges(sourceRepositoryPath: string, options?: { confirmation?: boolean; deleteFromSource?: boolean; untracked?: boolean }): Promise<void> {
|
||||
return this.#repository.migrateChanges(sourceRepositoryPath, options);
|
||||
}
|
||||
|
||||
generateRandomBranchName(): Promise<string | undefined> {
|
||||
return this.#repository.generateRandomBranchName();
|
||||
}
|
||||
}
|
||||
|
||||
export class ApiGit implements Git {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Model } from '../model';
|
||||
import { GitExtension, Repository, API } from './git';
|
||||
import type { GitExtension, Repository, API } from './git';
|
||||
import { ApiRepository, ApiImpl } from './api1';
|
||||
import { Event, EventEmitter } from 'vscode';
|
||||
import { CloneManager } from '../cloneManager';
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import type * as git from './git';
|
||||
|
||||
export type ForcePushMode = git.ForcePushMode;
|
||||
export type RefType = git.RefType;
|
||||
export type Status = git.Status;
|
||||
export type GitErrorCodes = git.GitErrorCodes;
|
||||
|
||||
export const ForcePushMode = Object.freeze({
|
||||
Force: 0,
|
||||
ForceWithLease: 1,
|
||||
ForceWithLeaseIfIncludes: 2,
|
||||
}) satisfies typeof git.ForcePushMode;
|
||||
|
||||
export const RefType = Object.freeze({
|
||||
Head: 0,
|
||||
RemoteHead: 1,
|
||||
Tag: 2,
|
||||
}) satisfies typeof git.RefType;
|
||||
|
||||
export const Status = Object.freeze({
|
||||
INDEX_MODIFIED: 0,
|
||||
INDEX_ADDED: 1,
|
||||
INDEX_DELETED: 2,
|
||||
INDEX_RENAMED: 3,
|
||||
INDEX_COPIED: 4,
|
||||
|
||||
MODIFIED: 5,
|
||||
DELETED: 6,
|
||||
UNTRACKED: 7,
|
||||
IGNORED: 8,
|
||||
INTENT_TO_ADD: 9,
|
||||
INTENT_TO_RENAME: 10,
|
||||
TYPE_CHANGED: 11,
|
||||
|
||||
ADDED_BY_US: 12,
|
||||
ADDED_BY_THEM: 13,
|
||||
DELETED_BY_US: 14,
|
||||
DELETED_BY_THEM: 15,
|
||||
BOTH_ADDED: 16,
|
||||
BOTH_DELETED: 17,
|
||||
BOTH_MODIFIED: 18,
|
||||
}) satisfies typeof git.Status;
|
||||
|
||||
export const GitErrorCodes = Object.freeze({
|
||||
BadConfigFile: 'BadConfigFile',
|
||||
BadRevision: 'BadRevision',
|
||||
AuthenticationFailed: 'AuthenticationFailed',
|
||||
NoUserNameConfigured: 'NoUserNameConfigured',
|
||||
NoUserEmailConfigured: 'NoUserEmailConfigured',
|
||||
NoRemoteRepositorySpecified: 'NoRemoteRepositorySpecified',
|
||||
NotAGitRepository: 'NotAGitRepository',
|
||||
NotASafeGitRepository: 'NotASafeGitRepository',
|
||||
NotAtRepositoryRoot: 'NotAtRepositoryRoot',
|
||||
Conflict: 'Conflict',
|
||||
StashConflict: 'StashConflict',
|
||||
UnmergedChanges: 'UnmergedChanges',
|
||||
PushRejected: 'PushRejected',
|
||||
ForcePushWithLeaseRejected: 'ForcePushWithLeaseRejected',
|
||||
ForcePushWithLeaseIfIncludesRejected: 'ForcePushWithLeaseIfIncludesRejected',
|
||||
RemoteConnectionError: 'RemoteConnectionError',
|
||||
DirtyWorkTree: 'DirtyWorkTree',
|
||||
CantOpenResource: 'CantOpenResource',
|
||||
GitNotFound: 'GitNotFound',
|
||||
CantCreatePipe: 'CantCreatePipe',
|
||||
PermissionDenied: 'PermissionDenied',
|
||||
CantAccessRemote: 'CantAccessRemote',
|
||||
RepositoryNotFound: 'RepositoryNotFound',
|
||||
RepositoryIsLocked: 'RepositoryIsLocked',
|
||||
BranchNotFullyMerged: 'BranchNotFullyMerged',
|
||||
NoRemoteReference: 'NoRemoteReference',
|
||||
InvalidBranchName: 'InvalidBranchName',
|
||||
BranchAlreadyExists: 'BranchAlreadyExists',
|
||||
NoLocalChanges: 'NoLocalChanges',
|
||||
NoStashFound: 'NoStashFound',
|
||||
LocalChangesOverwritten: 'LocalChangesOverwritten',
|
||||
NoUpstreamBranch: 'NoUpstreamBranch',
|
||||
IsInSubmodule: 'IsInSubmodule',
|
||||
WrongCase: 'WrongCase',
|
||||
CantLockRef: 'CantLockRef',
|
||||
CantRebaseMultipleBranches: 'CantRebaseMultipleBranches',
|
||||
PatchDoesNotApply: 'PatchDoesNotApply',
|
||||
NoPathFound: 'NoPathFound',
|
||||
UnknownPath: 'UnknownPath',
|
||||
EmptyCommitMessage: 'EmptyCommitMessage',
|
||||
BranchFastForwardRejected: 'BranchFastForwardRejected',
|
||||
BranchNotYetBorn: 'BranchNotYetBorn',
|
||||
TagConflict: 'TagConflict',
|
||||
CherryPickEmpty: 'CherryPickEmpty',
|
||||
CherryPickConflict: 'CherryPickConflict',
|
||||
WorktreeContainsChanges: 'WorktreeContainsChanges',
|
||||
WorktreeAlreadyExists: 'WorktreeAlreadyExists',
|
||||
WorktreeBranchAlreadyUsed: 'WorktreeBranchAlreadyUsed',
|
||||
}) satisfies Record<keyof typeof git.GitErrorCodes, string>;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user