diff --git a/.eslintignore b/.eslintignore index 108610063cd..2d9021afbb8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -30,7 +30,15 @@ **/src/vs/*/**/*.d.ts **/src/vs/base/test/common/filters.perf.data.js **/src/vs/loader.js +**/src2/**/dompurify.js +**/src2/**/marked.js +**/src2/**/semver.js +**/src2/typings/**/*.d.ts +**/src2/vs/*/**/*.d.ts +**/src2/vs/base/test/common/filters.perf.data.js +**/src2/vs/loader.js **/test/unit/assert.js +**/test/unit/assert-esm.js **/test/automation/out/** **/typings/** **/src/react.js diff --git a/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts b/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts index ae3089036a6..9d3044f50f4 100644 --- a/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts +++ b/.eslintplugin/code-ensure-no-disposables-leak-in-test.ts @@ -12,7 +12,8 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul type: 'problem', messages: { ensure: 'Suites should include a call to `ensureNoDisposablesAreLeakedInTestSuite()` to ensure no disposables are leaked in tests.' - } + }, + fixable: 'code' }; create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener { @@ -30,6 +31,10 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul context.report({ node, messageId: 'ensure', + fix: (fixer) => { + const updatedSrc = src.replace(/(suite\(.*\n)/, '$1\n\tensureNoDisposablesAreLeakedInTestSuite();\n'); + return fixer.replaceText(node, updatedSrc); + } }); } }, diff --git a/.eslintrc.json b/.eslintrc.json index 2b56c505d4f..eecde4d7484 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -792,7 +792,8 @@ "vs/base/~", "vs/base/parts/*/~", "vs/platform/*/~", - "vs/editor/~" + "vs/editor/~", + "@vscode/tree-sitter-wasm" // node module allowed even in /common/ ] }, { @@ -1080,7 +1081,7 @@ ] }, { - "target": "src/vs/{loader.d.ts,css.ts,css.build.ts,monaco.d.ts,nls.ts}", + "target": "src/vs/{loader.d.ts,css.ts,css.build.ts,monaco.d.ts,nls.messages.ts,nls.ts}", "restrictions": [] }, { @@ -1094,7 +1095,7 @@ }, // --- End Positron --- { - "target": "src/{bootstrap-amd.js,bootstrap-fork.js,bootstrap-node.js,bootstrap-window.js,bootstrap.js,cli.js,main.js,server-cli.js,server-main.js}", + "target": "src/{bootstrap-amd.js,bootstrap-fork.js,bootstrap-node.js,bootstrap-window.js,cli.js,main.js,server-cli.js,server-main.js,bootstrap-cli.js,bootstrap-server.js}", "restrictions": [] } ] diff --git a/.github/commands.json b/.github/commands.json index 44480916133..38da97915a2 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -156,6 +156,37 @@ "addLabel": "confirmation-pending", "removeLabel": "confirmed" }, + { + "type": "comment", + "name": "needsMoreInfo", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "updateLabels", + "addLabel": "~info-needed" + }, + { + "type": "comment", + "name": "needsPerfInfo", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "addLabel": "info-needed", + "comment": "Thanks for creating this issue regarding performance! Please follow this guide to help us diagnose performance issues: https://github.com/microsoft/vscode/wiki/Performance-Issues \n\nHappy Coding!" + }, + { + "type": "comment", + "name": "jsDebugLogs", + "action": "updateLabels", + "addLabel": "info-needed", + "comment": "Please collect trace logs using the following instructions:\n\n> If you're able to, add `\"trace\": true` to your `launch.json` and reproduce the issue. The location of the log file on your disk will be written to the Debug Console. Share that with us.\n>\n> ⚠️ This log file will not contain source code, but will contain file paths. You can drop it into https://microsoft.github.io/vscode-pwa-analyzer/index.html to see what it contains. If you'd rather not share the log publicly, you can email it to connor@xbox.com" + }, { "type": "comment", "name": "closedWith", @@ -427,6 +458,32 @@ "addLabel": "*caused-by-extension", "comment": "It looks like this is caused by the Copilot extension. Please file the issue in the [Copilot Discussion Forum](https://github.com/community/community/discussions/categories/copilot). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting guidelines](https://aka.ms/vscodeissuereporting) for more information.\n\nHappy Coding!" }, + { + "type": "comment", + "name": "gifPlease", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "comment", + "addLabel": "info-needed", + "comment": "Thanks for reporting this issue! Unfortunately, it's hard for us to understand what issue you're seeing. Please help us out by providing a screen recording showing exactly what isn't working as expected. While we can work with most standard formats, `.gif` files are preferred as they are displayed inline on GitHub. You may find https://gifcap.dev helpful as a browser-based gif recording tool.\n\nIf the issue depends on keyboard input, you can help us by enabling screencast mode for the recording (`Developer: Toggle Screencast Mode` in the command palette). Lastly, please attach this file via the GitHub web interface as emailed responses will strip files out from the issue.\n\nHappy coding!" + }, + { + "type": "comment", + "name": "confirmPlease", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "comment", + "addLabel": "info-needed", + "comment": "Please diagnose the root cause of the issue by running the command `F1 > Help: Troubleshoot Issue` and following the instructions. Once you have done that, please update the issue with the results.\n\nHappy Coding!" + }, { "__comment__": "Allows folks on the team to label issues by commenting: `\\label My-Label` ", "type": "comment", @@ -457,5 +514,29 @@ "addLabel": "verification-steps-needed", "removeLabel": "~verification-steps-needed", "comment": "Friendly ping! Looks like this issue requires some further steps to be verified. Please provide us with the steps necessary to verify this issue." + }, + { + "type": "label", + "name": "~info-needed", + "action": "updateLabels", + "addLabel": "info-needed", + "removeLabel": "~info-needed", + "comment": "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting). Please take the time to review these and update the issue.\n\nHappy Coding!" + }, + { + "type": "label", + "name": "~version-info-needed", + "action": "updateLabels", + "addLabel": "info-needed", + "removeLabel": "~version-info-needed", + "comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number, or in some other way doesn't follow our [issue reporting guidelines](https://aka.ms/vscodeissuereporting). Please take the time to review these and update the issue.\n\nHappy Coding!" + }, + { + "type": "label", + "name": "~confirmation-needed", + "action": "updateLabels", + "addLabel": "info-needed", + "removeLabel": "~confirmation-needed", + "comment": "Please diagnose the root cause of the issue by running the command `F1 > Help: Troubleshoot Issue` and following the instructions. Once you have done that, please update the issue with the results.\n\nHappy Coding!" } ] diff --git a/.github/workflows/author-verified.yml b/.github/workflows/author-verified.yml deleted file mode 100644 index f914be2f71b..00000000000 --- a/.github/workflows/author-verified.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Author Verified -on: - issues: - types: [closed] - -# also make changes in ./on-label.yml -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released') - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released') - run: npm install --production --prefix ./actions - - name: Run Author Verified - if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released') - uses: ./actions/author-verified - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - requestVerificationComment: "This bug has been fixed in the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by commenting `/verified` if things are now working as expected.\n\nIf things still don't seem right, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!" - releasedLabel: insiders-released - verifiedLabel: verified - authorVerificationRequestedLabel: author-verification-requested diff --git a/.github/workflows/bad-tag.yml b/.github/workflows/bad-tag.yml deleted file mode 100644 index bc964fb0582..00000000000 --- a/.github/workflows/bad-tag.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Bad Tag -on: - create - -jobs: - main: - runs-on: ubuntu-latest - if: github.event.ref == '1.999.0' - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - name: Run Bad Tag - uses: ./actions/tag-alert - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - tag-name: '1.999.0' diff --git a/.github/workflows/deep-classifier-assign-monitor.yml b/.github/workflows/deep-classifier-assign-monitor.yml deleted file mode 100644 index a61f9cfb137..00000000000 --- a/.github/workflows/deep-classifier-assign-monitor.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: "Deep Classifier: Assign Monitor" -on: - issues: - types: [assigned] - -jobs: - main: - runs-on: ubuntu-latest - if: ${{ contains(github.event.issue.labels.*.name, 'triage-needed') }} - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - name: "Run Classifier: Monitor" - uses: ./actions/classifier-deep/monitor - with: - botName: VSCodeTriageBot - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} diff --git a/.github/workflows/deep-classifier-unassign-monitor.yml b/.github/workflows/deep-classifier-unassign-monitor.yml deleted file mode 100644 index 52ac0d3ddcd..00000000000 --- a/.github/workflows/deep-classifier-unassign-monitor.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: "Deep Classifier: Unassign Monitor" -on: - issues: - types: [unassigned] - -jobs: - main: - runs-on: ubuntu-latest - if: ${{ ! contains(github.event.issue.labels.*.name, 'triage-needed') }} - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - name: "Run Classifier: Monitor" - uses: ./actions/classifier-deep/monitor - with: - botName: VSCodeTriageBot - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} diff --git a/.github/workflows/english-please.yml b/.github/workflows/english-please.yml deleted file mode 100644 index 9e04d6d549c..00000000000 --- a/.github/workflows/english-please.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: English Please -on: - issues: - types: [edited] - -# also make changes in ./on-label.yml and ./on-open.yml -jobs: - main: - runs-on: ubuntu-latest - if: contains(github.event.issue.labels.*.name, '*english-please') - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - name: Run English Please - uses: ./actions/english-please - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} - nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "info-needed" - translatorRequestedLabelPrefix: "translation-required-" - translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/feature-request.yml b/.github/workflows/feature-request.yml deleted file mode 100644 index 7913fc461ec..00000000000 --- a/.github/workflows/feature-request.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Feature Request Manager -on: - repository_dispatch: - types: [trigger-feature-request-manager] - issues: - types: [milestoned] - -# also make changes in ./on-label.yml -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request') - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - path: ./actions - ref: stable - - name: Install Actions - if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request') - run: npm install --production --prefix ./actions - - name: Run Feature Request Manager - if: github.event_name != 'issues' || contains(github.event.issue.labels.*.name, 'feature-request') - uses: ./actions/feature-request - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - repo: "vscode" - owner: "microsoft" - candidateMilestoneID: 107 - candidateMilestoneName: Backlog Candidates - backlogMilestoneID: 8 - featureRequestLabel: feature-request - upvotesRequired: 20 - numCommentsOverride: 20 - initComment: "This feature request is now a candidate for our backlog. The community has 60 days to [upvote](https://github.com/microsoft/vscode/wiki/Issues-Triaging#up-voting-a-feature-request) the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - warnComment: "This feature request has not yet received the 20 community [upvotes](https://github.com/microsoft/vscode/wiki/Issues-Triaging#up-voting-a-feature-request) it takes to make to our backlog. 10 days to go. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - acceptComment: ":slightly_smiling_face: This feature request received a sufficient number of community upvotes and we moved it to our backlog. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - rejectComment: ":slightly_frowning_face: In the last 60 days, this feature request has received less than 20 community upvotes and we closed it. Still a big Thank You to you for taking the time to create this issue! To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - warnDays: 10 - closeDays: 60 - milestoneDelaySeconds: 60 diff --git a/.github/workflows/on-comment.yml b/.github/workflows/on-comment.yml deleted file mode 100644 index 089aa77c1e7..00000000000 --- a/.github/workflows/on-comment.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: On Comment -on: - issue_comment: - types: [created] - -# also make changes in ./on-label.yml -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - path: ./actions - ref: stable - - name: Install Actions - run: npm install --production --prefix ./actions - - name: Run Commands - uses: ./actions/commands - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - config-path: commands - - name: "Run Release Pipeline Labeler" - uses: ./actions/release-pipeline - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - notYetReleasedLabel: unreleased - insidersReleasedLabel: insiders-released diff --git a/.github/workflows/on-label.yml b/.github/workflows/on-label.yml deleted file mode 100644 index bf563734017..00000000000 --- a/.github/workflows/on-label.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: On Label -on: - issues: - types: [labeled] - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - # source of truth in ./author-verified.yml - - name: Run Author Verified - if: contains(github.event.issue.labels.*.name, 'author-verification-requested') && contains(github.event.issue.labels.*.name, 'insiders-released') - uses: ./actions/author-verified - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - requestVerificationComment: "This bug has been fixed in the latest release of [VS Code Insiders](https://code.visualstudio.com/insiders/)!\n\n@${author}, you can help us out by commenting `/verified` if things are now working as expected.\n\nIf things still don't seem right, please ensure you're on version ${commit} of Insiders (today's or later - you can use `Help: About` in the command palette to check), and leave a comment letting us know what isn't working as expected.\n\nHappy Coding!" - releasedLabel: insiders-released - verifiedLabel: verified - authorVerificationRequestedLabel: author-verification-requested - - - # also make changes in ./on-comment.yml - - name: Run Commands - uses: ./actions/commands - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - config-path: commands - - # source of truth in ./feature-request.yml - - name: Run Feature Request Manager - if: contains(github.event.issue.labels.*.name, 'feature-request') - uses: ./actions/feature-request - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - candidateMilestoneID: 107 - candidateMilestoneName: Backlog Candidates - backlogMilestoneID: 8 - featureRequestLabel: feature-request - upvotesRequired: 20 - numCommentsOverride: 20 - initComment: "This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - warnComment: "This feature request has not yet received the 20 community upvotes it takes to make to our backlog. 10 days to go. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding" - acceptComment: ":slightly_smiling_face: This feature request received a sufficient number of community upvotes and we moved it to our backlog. To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - rejectComment: ":slightly_frowning_face: In the last 60 days, this feature request has received less than 20 community upvotes and we closed it. Still a big Thank You to you for taking the time to create this issue! To learn more about how we handle feature requests, please see our [documentation](https://aka.ms/vscode-issue-lifecycle).\n\nHappy Coding!" - warnDays: 10 - closeDays: 60 - milestoneDelaySeconds: 60 - - # source of truth in ./test-plan-item-validator.yml - - name: Run Test Plan Item Validator - if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') - uses: ./actions/test-plan-item-validator - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - refLabel: on-testplan - label: testplan-item - invalidLabel: invalid-testplan-item - comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. - - # source of truth in ./english-please.yml - - name: Run English Please - if: contains(github.event.issue.labels.*.name, '*english-please') - uses: ./actions/english-please - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} - nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "info-needed" - translatorRequestedLabelPrefix: "translation-required-" - translatorRequestedLabelColor: "c29cff" diff --git a/.github/workflows/on-open.yml b/.github/workflows/on-open.yml deleted file mode 100644 index 62cdbff683b..00000000000 --- a/.github/workflows/on-open.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: On Open -on: - issues: - types: [opened] - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - - name: Check for Validity - uses: ./actions/validity-checker - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - - - name: Run CopyCat (VSCodeTriageBot/testissues) - if: github.event.issue.user.login != 'ghost' - uses: ./actions/copycat - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - destinationOwner: VSCodeTriageBot - destinationRepo: testissues - - - name: Run New Release - if: github.event.issue.user.login != 'ghost' - uses: ./actions/new-release - with: - label: new release - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - labelColor: "006b75" - labelDescription: Issues found in a recent release of VS Code - oldVersionMessage: "Thanks for creating this issue! It looks like you may be using an old version of VS Code, the latest stable release is {currentVersion}. Please try upgrading to the latest version and checking whether this issue remains.\n\nHappy Coding!" - days: 5 - - - name: Run Clipboard Labeler - if: github.event.issue.user.login != 'ghost' - uses: ./actions/regex-labeler - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - label: "invalid" - mustNotMatch: "^We have written the needed data into your clipboard because it was too large to send\\. Please paste\\.$" - comment: "It looks like you're using the VS Code Issue Reporter but did not paste the text generated into the created issue. We've closed this issue, please open a new one containing the text we placed in your clipboard.\n\nHappy Coding!" - - - name: Run Clipboard Labeler (Chinese) - if: github.event.issue.user.login != 'ghost' - uses: ./actions/regex-labeler - with: - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - label: "invalid" - mustNotMatch: "^所需的数据太大,无法直接发送。我们已经将其写入剪贴板,请粘贴。$" - comment: "看起来您正在使用 VS Code 问题报告程序,但是没有将生成的文本粘贴到创建的问题中。我们将关闭这个问题,请使用剪贴板中的内容创建一个新的问题。\n\n祝您使用愉快!" - - # source of truth in ./english-please.yml - - name: Run English Please - if: github.event.issue.user.login != 'ghost' - uses: ./actions/english-please - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - cognitiveServicesAPIKey: ${{secrets.AZURE_TEXT_TRANSLATOR_KEY}} - nonEnglishLabel: "*english-please" - needsMoreInfoLabel: "info-needed" - translatorRequestedLabelPrefix: "translation-required-" - translatorRequestedLabelColor: "c29cff" - # source of truth in ./test-plan-item-validator.yml - - name: Run Test Plan Item Validator - if: github.event.issue.user.login != 'ghost' - uses: ./actions/test-plan-item-validator - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - refLabel: on-testplan - label: testplan-item - invalidLabel: invalid-testplan-item - comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. - diff --git a/.github/workflows/on-reopen.yml b/.github/workflows/on-reopen.yml deleted file mode 100644 index d29de326c53..00000000000 --- a/.github/workflows/on-reopen.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: On Reopen -on: - issues: - types: [reopened] - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Install Actions - run: npm install --production --prefix ./actions - - - name: Check for Validity - uses: ./actions/validity-checker - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} diff --git a/.github/workflows/positron-full-test.yml b/.github/workflows/positron-full-test.yml index 21a95f85aad..b9fe6639910 100644 --- a/.github/workflows/positron-full-test.yml +++ b/.github/workflows/positron-full-test.yml @@ -80,9 +80,9 @@ jobs: path: | extensions extensions/**/node_modules - key: extensions-v3-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} + key: extensions-v4-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} restore-keys: | - extensions-v3-${{ runner.os }}- + extensions-v4-${{ runner.os }}- - name: Restore cache for remote id: cache-remote diff --git a/.github/workflows/positron-merge-to-main.yml b/.github/workflows/positron-merge-to-main.yml index 8f345c44b06..8bded3623f9 100644 --- a/.github/workflows/positron-merge-to-main.yml +++ b/.github/workflows/positron-merge-to-main.yml @@ -82,9 +82,9 @@ jobs: path: | extensions extensions/**/node_modules - key: extensions-v3-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} + key: extensions-v4-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} restore-keys: | - extensions-v3-${{ runner.os }}- + extensions-v4-${{ runner.os }}- - name: Restore cache for remote id: cache-remote @@ -140,7 +140,7 @@ jobs: path: | extensions extensions/**/node_modules - key: extensions-v3-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} + key: extensions-v4-${{ runner.os }}-${{ hashFiles('extensions/yarn.lock') }} - name: Cache remote node_modules if: always() && steps.cache-remote.outputs.cache-hit != 'true' diff --git a/.github/workflows/release-pipeline-labeler.yml b/.github/workflows/release-pipeline-labeler.yml deleted file mode 100644 index 87e188a02ab..00000000000 --- a/.github/workflows/release-pipeline-labeler.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: "Release Pipeline Labeler" -on: - issues: - types: [closed, reopened] - repository_dispatch: - types: [released-insider] - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - ref: stable - path: ./actions - - name: Checkout Repo - if: github.event_name != 'issues' - uses: actions/checkout@v4 - with: - path: ./repo - fetch-depth: 0 - - name: Install Actions - run: npm install --production --prefix ./actions - - name: "Run Release Pipeline Labeler" - uses: ./actions/release-pipeline - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - appInsightsKey: ${{secrets.TRIAGE_ACTIONS_APP_INSIGHTS}} - notYetReleasedLabel: unreleased - insidersReleasedLabel: insiders-released diff --git a/.github/workflows/telemetry.yml b/.github/workflows/telemetry.yml index d463a0e2eca..d29ea6c58da 100644 --- a/.github/workflows/telemetry.yml +++ b/.github/workflows/telemetry.yml @@ -16,4 +16,4 @@ jobs: - name: 'Run vscode-telemetry-extractor' run: 'npx --package=@vscode/telemetry-extractor --yes vscode-telemetry-extractor -s .' env: - GITHUB_TOKEN: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-plan-item-validator.yml b/.github/workflows/test-plan-item-validator.yml deleted file mode 100644 index 117eaf6908a..00000000000 --- a/.github/workflows/test-plan-item-validator.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Test Plan Item Validator -on: - issues: - types: [edited] - -# also edit in ./on-label.yml and ./on-open.yml -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout Actions - if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') - uses: actions/checkout@v4 - with: - repository: "microsoft/vscode-github-triage-actions" - path: ./actions - ref: stable - - name: Install Actions - if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') - run: npm install --production --prefix ./actions - - name: Run Test Plan Item Validator - if: contains(github.event.issue.labels.*.name, 'testplan-item') || contains(github.event.issue.labels.*.name, 'invalid-testplan-item') - uses: ./actions/test-plan-item-validator - with: - token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - refLabel: on-testplan - label: testplan-item - invalidLabel: invalid-testplan-item - comment: Invalid test plan item. See errors below and the [test plan item spec](https://github.com/microsoft/vscode/wiki/Writing-Test-Plan-Items) for more information. This comment will go away when the issues are resolved. diff --git a/.vscode-test.js b/.vscode-test.js index 0f623d16dd7..aaa916f465f 100644 --- a/.vscode-test.js +++ b/.vscode-test.js @@ -61,8 +61,12 @@ const extensions = [ label: 'positron-connections', workspaceFolder: path.join(os.tmpdir(), `positron-connections-${Math.floor(Math.random() * 100000)}`), mocha: { timeout: 60_000 } - } + }, // --- End Positron --- + { + label: 'microsoft-authentication', + mocha: { timeout: 60_000 } + } ]; diff --git a/.vscode/extensions/vscode-selfhost-test-provider/src/testOutputScanner.ts b/.vscode/extensions/vscode-selfhost-test-provider/src/testOutputScanner.ts index f8e70b4d9cd..296ed1e9f12 100644 --- a/.vscode/extensions/vscode-selfhost-test-provider/src/testOutputScanner.ts +++ b/.vscode/extensions/vscode-selfhost-test-provider/src/testOutputScanner.ts @@ -290,7 +290,7 @@ export async function scanTestOutput( enqueueExitBlocker( (async () => { const stackInfo = await deriveStackLocations(store, rawErr, tcase!); - let message: vscode.TestMessage2; + let message: vscode.TestMessage; if (hasDiff) { message = new vscode.TestMessage(tryMakeMarkdown(err)); diff --git a/.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json b/.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json index df98ed3e695..56d6859c3e3 100644 --- a/.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json +++ b/.vscode/extensions/vscode-selfhost-test-provider/tsconfig.json @@ -11,7 +11,6 @@ "src/**/*", "../../../src/vscode-dts/vscode.d.ts", "../../../src/vscode-dts/vscode.proposed.testObserver.d.ts", - "../../../src/vscode-dts/vscode.proposed.testMessageStackTrace.d.ts", "../../../src/vscode-dts/vscode.proposed.testRelatedCode.d.ts", "../../../src/vscode-dts/vscode.proposed.attributableCoverage.d.ts" ] diff --git a/.vscode/notebooks/api.github-issues b/.vscode/notebooks/api.github-issues index c5dda6b26af..c402cca3836 100644 --- a/.vscode/notebooks/api.github-issues +++ b/.vscode/notebooks/api.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"July 2024\"" + "value": "$REPO=repo:microsoft/vscode\n$MILESTONE=milestone:\"August 2024\"" }, { "kind": 1, diff --git a/.vscode/notebooks/endgame.github-issues b/.vscode/notebooks/endgame.github-issues index 215d9dcee40..450ba41835f 100644 --- a/.vscode/notebooks/endgame.github-issues +++ b/.vscode/notebooks/endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$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\r\n\r\n$MILESTONE=milestone:\"July 2024\"" + "value": "$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\n\n$MILESTONE=milestone:\"August 2024\"" }, { "kind": 1, diff --git a/.vscode/notebooks/my-endgame.github-issues b/.vscode/notebooks/my-endgame.github-issues index 9bf6b335736..df0f8a92998 100644 --- a/.vscode/notebooks/my-endgame.github-issues +++ b/.vscode/notebooks/my-endgame.github-issues @@ -7,7 +7,7 @@ { "kind": 2, "language": "github-issues", - "value": "$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\n\n$MILESTONE=milestone:\"July 2024\"\n\n$MINE=assignee:@me" + "value": "$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\n\n$MILESTONE=milestone:\"August 2024\"\n\n$MINE=assignee:@me" }, { "kind": 1, diff --git a/.vscode/notebooks/my-work.github-issues b/.vscode/notebooks/my-work.github-issues index 1e539f4c3c1..979180e758a 100644 --- a/.vscode/notebooks/my-work.github-issues +++ b/.vscode/notebooks/my-work.github-issues @@ -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\n\n// current milestone name\n$MILESTONE=milestone:\"July 2024\"\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\n\n// current milestone name\n$MILESTONE=milestone:\"August 2024\"\n" }, { "kind": 1, diff --git a/.vscode/notebooks/vscode-dev.github-issues b/.vscode/notebooks/vscode-dev.github-issues index 53fad82e6d9..db480b64bd8 100644 --- a/.vscode/notebooks/vscode-dev.github-issues +++ b/.vscode/notebooks/vscode-dev.github-issues @@ -2,7 +2,7 @@ { "kind": 2, "language": "github-issues", - "value": "$milestone=milestone:\"November 2023\"" + "value": "$milestone=milestone:\"August 2024\"" }, { "kind": 1, diff --git a/.vscode/settings.json b/.vscode/settings.json index ff39e6ad11e..adf10bc4cd1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -32,6 +32,7 @@ "src/vs/base/test/common/filters.perf.data.js": true, "src/vs/base/test/node/uri.perf.data.txt": true, "src/vs/workbench/api/test/browser/extHostDocumentData.test.perf-data.ts": true, + "src/vs/base/test/node/uri.test.data.txt": true, "src/vs/editor/test/node/diffing/fixtures/**": true, }, "files.readonlyInclude": { @@ -50,6 +51,7 @@ "test/smoke/out/**": true, "test/automation/out/**": true, "test/integration/browser/out/**": true, + "src2/**": true, }, "files.readonlyExclude": { "build/builtin/*.js": true, @@ -169,10 +171,9 @@ "editor.wordWrap": "on" }, "css.format.spaceAroundSelectorSeparator": true, - "inlineChat.mode": "live", "editor.rulers": [ 100 ], - "inlineChat.experimental.textButtons": true, - "typescript.enablePromptUseWorkspaceTsdk": true + "typescript.enablePromptUseWorkspaceTsdk": true, + "inlineChat.experimental.onlyZoneWidget": true } diff --git a/.vscode/shared.code-snippets b/.vscode/shared.code-snippets index c30e9160b0e..a6f462b79f2 100644 --- a/.vscode/shared.code-snippets +++ b/.vscode/shared.code-snippets @@ -49,5 +49,23 @@ "private readonly _onDid$1 = new Emitter<$2>();", "readonly onDid$1: Event<$2> = this._onDid$1.event;" ], + }, + "esm-comment": { + "scope": "typescript,javascript", + "prefix": "esm-comment", + "body": [ + "// ESM-comment-begin", + "$SELECTION$0", + "// ESM-comment-end", + ] + }, + "esm-uncomment": { + "scope": "typescript,javascript", + "prefix": "esm-uncomment", + "body": [ + "// ESM-uncomment-begin", + "// $SELECTION$0", + "// ESM-uncomment-end", + ] } } diff --git a/.yarnrc b/.yarnrc index 6d4a827644c..94e494ee938 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,5 +1,5 @@ disturl "https://electronjs.org/headers" -target "30.1.2" -ms_build_id "9870757" +target "30.4.0" +ms_build_id "10073054" runtime "electron" build_from_source "true" diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index d050b23f52a..4bcdcc47c9e 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -263,6 +263,34 @@ suitability for any purpose. --------------------------------------------------------- +cacheable-request 7.0.4 - MIT + + +Copyright (c) cacheable-request authors + +MIT License + +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. +--------------------------------------------------------- + +--------------------------------------------------------- + Colorsublime-Themes 0.1.0 https://github.com/Colorsublime/Colorsublime-Themes @@ -890,7 +918,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI --------------------------------------------------------- -JuliaEditorSupport/atom-language-julia 0.22.1 - MIT +JuliaEditorSupport/atom-language-julia 0.23.0 - MIT https://github.com/JuliaEditorSupport/atom-language-julia The atom-language-julia package is licensed under the MIT "Expat" License: @@ -1241,7 +1269,7 @@ THE SOFTWARE. --------------------------------------------------------- -marked 4.1.0 - MIT +marked 14.0.0 - MIT https://github.com/markedjs/marked information @@ -1534,7 +1562,7 @@ SOFTWARE. --------------------------------------------------------- -RedCMD/YAML-Syntax-Highlighter 1.0.1 - MIT +RedCMD/YAML-Syntax-Highlighter 1.1.1 - MIT https://github.com/RedCMD/YAML-Syntax-Highlighter MIT License diff --git a/build/.cachesalt b/build/.cachesalt index d7d415d3213..58a1efc1632 100644 --- a/build/.cachesalt +++ b/build/.cachesalt @@ -1 +1 @@ -2024-07-04T16:31:11.121Z +2024-08-14T18:12:43.548Z diff --git a/build/.moduleignore b/build/.moduleignore index ed9c0a6497d..e103872345c 100644 --- a/build/.moduleignore +++ b/build/.moduleignore @@ -96,10 +96,13 @@ node-pty/lib/*.test.js node-pty/tools/** node-pty/deps/** node-pty/scripts/** +node-pty/third_party/** !node-pty/build/Release/spawn-helper !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node +!node-pty/build/Release/conpty/conpty.dll +!node-pty/build/Release/conpty/OpenConsole.exe @parcel/watcher/binding.gyp @parcel/watcher/build/** @@ -163,7 +166,7 @@ typescript/lib/tsserverlibrary.js jschardet/index.js jschardet/src/** -jschardet/dist/jschardet.js +# TODO@esm uncomment when we can use jschardet.min.js again jschardet/dist/jschardet.js es6-promise/lib/** diff --git a/build/.webignore b/build/.webignore index 15935edce8a..837366b67f7 100644 --- a/build/.webignore +++ b/build/.webignore @@ -14,7 +14,7 @@ jschardet/index.js jschardet/src/** -jschardet/dist/jschardet.js +# TODO@esm uncomment when we can use jschardet.min.js again jschardet/dist/jschardet.js vscode-textmate/webpack.config.js @@ -38,6 +38,7 @@ vscode-textmate/webpack.config.js # This makes sure the model is included in the package !@vscode/vscode-languagedetection/model/** +!@vscode/tree-sitter-wasm/wasm/** # Ensure only the required telemetry pieces are loaded in web to reduce bundle size @microsoft/1ds-core-js/** @@ -45,7 +46,9 @@ vscode-textmate/webpack.config.js @microsoft/applicationinsights-core-js/** @microsoft/applicationinsights-shims/** !@microsoft/1ds-core-js/dist/ms.core.min.js +!@microsoft/1ds-core-js/bundle/ms.core.min.js !@microsoft/1ds-post-js/dist/ms.post.min.js +!@microsoft/1ds-post-js/bundle/ms.post.min.js !@microsoft/applicationinsights-core-js/browser/applicationinsights-core-js.min.js !@microsoft/applicationinsights-shims/dist/umd/applicationinsights-shims.min.js diff --git a/build/azure-pipelines/common/publish.js b/build/azure-pipelines/common/publish.js index c990e3a7146..aa185ed8369 100644 --- a/build/azure-pipelines/common/publish.js +++ b/build/azure-pipelines/common/publish.js @@ -389,14 +389,8 @@ function getPlatform(product, os, arch, type, isLegacy) { } } case 'server': - if (arch === 'arm64') { - throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); - } return `server-win32-${arch}`; case 'web': - if (arch === 'arm64') { - throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); - } return `server-win32-${arch}-web`; case 'cli': return `cli-win32-${arch}`; diff --git a/build/azure-pipelines/common/publish.ts b/build/azure-pipelines/common/publish.ts index 75065ffa2d3..652cd168335 100644 --- a/build/azure-pipelines/common/publish.ts +++ b/build/azure-pipelines/common/publish.ts @@ -550,14 +550,8 @@ function getPlatform(product: string, os: string, arch: string, type: string, is } } case 'server': - if (arch === 'arm64') { - throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); - } return `server-win32-${arch}`; case 'web': - if (arch === 'arm64') { - throw new Error(`Unrecognized: ${product} ${os} ${arch} ${type}`); - } return `server-win32-${arch}-web`; case 'cli': return `cli-win32-${arch}`; diff --git a/build/azure-pipelines/darwin/product-build-darwin-test.yml b/build/azure-pipelines/darwin/product-build-darwin-test.yml index 92fe6eb715e..c5f9dfb0036 100644 --- a/build/azure-pipelines/darwin/product-build-darwin-test.yml +++ b/build/azure-pipelines/darwin/product-build-darwin-test.yml @@ -7,6 +7,9 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - script: yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -17,34 +20,56 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test.sh --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - - script: yarn test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - script: yarn test-browser-no-install --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) - timeoutInMinutes: 30 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-esm.sh --tfs "Unit Tests" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - script: yarn test-node-esm + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - script: yarn test-browser-esm-no-install --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) [ESM] + timeoutInMinutes: 30 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test.sh --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: yarn test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: yarn test-browser-no-install --sequential --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - - script: yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - script: yarn test-browser-no-install --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium & Webkit) - timeoutInMinutes: 30 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-esm.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - script: yarn test-node-esm --build + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - script: yarn test-browser-esm-no-install --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) [ESM] + timeoutInMinutes: 30 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: yarn test-node --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: yarn test-browser-no-install --sequential --build --browser chromium --browser webkit --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium & Webkit) + timeoutInMinutes: 30 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -69,24 +94,44 @@ steps: displayName: Build integration tests - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test-integration.sh --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-integration-esm.sh --tfs "Integration Tests" + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test-integration --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT="$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)" - APP_NAME="`ls $APP_ROOT | head -n 1`" - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT="$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)" + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + ./scripts/test-integration-esm.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT="$(agent.builddirectory)/VSCode-darwin-$(VSCODE_ARCH)" + APP_NAME="`ls $APP_ROOT | head -n 1`" + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME/Contents/MacOS/Electron" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-darwin-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser webkit env: diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index 11f69d735ac..ccb6b5b35e7 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -9,6 +9,9 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -101,6 +104,11 @@ steps: ELECTRON_SKIP_BINARY_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 GITHUB_TOKEN: "$(github-distro-mixin-password)" + # Avoid using dlopen to load Kerberos on macOS which can cause missing libraries + # https://github.com/mongodb-js/kerberos/commit/04044d2814ad1d01e77f1ce87f26b03d86692cf2 + # flipped the default to support legacy linux distros which shouldn't happen + # on macOS. + GYP_DEFINES: "kerberos_use_rtld=false" displayName: Install dependencies condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true')) @@ -169,6 +177,7 @@ steps: VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} + VSCODE_BUILD_ESM: ${{ parameters.VSCODE_BUILD_ESM }} - ${{ elseif and(ne(parameters.VSCODE_CIBUILD, true), ne(parameters.VSCODE_QUALITY, 'oss')) }}: - task: DownloadPipelineArtifact@2 diff --git a/build/azure-pipelines/linux/product-build-linux-legacy-server.yml b/build/azure-pipelines/linux/product-build-linux-legacy-server.yml index 26f02657e10..b3b505c1369 100644 --- a/build/azure-pipelines/linux/product-build-linux-legacy-server.yml +++ b/build/azure-pipelines/linux/product-build-linux-legacy-server.yml @@ -5,6 +5,9 @@ parameters: type: boolean - name: VSCODE_ARCH type: string + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - task: NodeTool@0 @@ -201,6 +204,7 @@ steps: VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: false + VSCODE_BUILD_ESM: ${{ parameters.VSCODE_BUILD_ESM }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 diff --git a/build/azure-pipelines/linux/product-build-linux-test.yml b/build/azure-pipelines/linux/product-build-linux-test.yml index 43673619b16..0b358a81914 100644 --- a/build/azure-pipelines/linux/product-build-linux-test.yml +++ b/build/azure-pipelines/linux/product-build-linux-test.yml @@ -10,6 +10,9 @@ parameters: - name: PUBLISH_TASK_NAME type: string default: PublishPipelineArtifact@0 + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - script: yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -33,36 +36,61 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test.sh --tfs "Unit Tests" - env: - DISPLAY: ":10" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-esm.sh --tfs "Unit Tests" + env: + DISPLAY: ":10" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - script: yarn test-node-esm + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - script: yarn test-browser-esm-no-install --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) [ESM] + timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test.sh --tfs "Unit Tests" + env: + DISPLAY: ":10" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: yarn test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: yarn test-browser-no-install --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 - - script: yarn test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - script: yarn test-browser-no-install --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 15 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test.sh --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - - script: yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - script: yarn test-browser-no-install --build --browser chromium --tfs "Browser Unit Tests" - env: - DEBUG: "*browser*" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-esm.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - script: yarn test-node-esm --build + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - script: yarn test-browser-esm-no-install --build --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) [ESM] + timeoutInMinutes: 15 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test.sh --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - script: yarn test-node --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - script: yarn test-browser-no-install --build --browser chromium --tfs "Browser Unit Tests" + env: + DEBUG: "*browser*" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 15 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - script: | @@ -88,11 +116,18 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - script: ./scripts/test-integration.sh --tfs "Integration Tests" - env: - DISPLAY: ":10" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: ./scripts/test-integration-esm.sh --tfs "Integration Tests" + env: + DISPLAY: ":10" + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: ./scripts/test-integration.sh --tfs "Integration Tests" + env: + DISPLAY: ":10" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser chromium displayName: Run integration tests (Browser, Chromium) @@ -103,20 +138,36 @@ steps: timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - script: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - set -e - APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) - APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") - INTEGRATION_TEST_APP_NAME="$APP_NAME" \ - INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ - ./scripts/test-integration.sh --build --tfs "Integration Tests" - env: - VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_APP_NAME="$APP_NAME" \ + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + ./scripts/test-integration-esm.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - script: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + set -e + APP_ROOT=$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH) + APP_NAME=$(node -p "require(\"$APP_ROOT/resources/app/product.json\").applicationName") + INTEGRATION_TEST_APP_NAME="$APP_NAME" \ + INTEGRATION_TEST_ELECTRON_PATH="$APP_ROOT/$APP_NAME" \ + ./scripts/test-integration.sh --build --tfs "Integration Tests" + env: + VSCODE_REMOTE_SERVER_PATH: $(agent.builddirectory)/vscode-server-linux-$(VSCODE_ARCH) + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - script: ./scripts/test-web-integration.sh --browser chromium env: @@ -150,7 +201,7 @@ steps: - script: yarn --cwd test/smoke compile displayName: Compile smoke tests - - script: yarn gulp compile-extension:markdown-language-features compile-extension-media compile-extension:vscode-test-resolver + - script: yarn gulp compile-extension:markdown-language-features compile-extension:ipynb compile-extension-media compile-extension:vscode-test-resolver displayName: Build extensions for smoke tests - script: yarn gulp node diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index d1d6bdb9191..2aa304e4fba 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -11,6 +11,9 @@ parameters: type: boolean - name: VSCODE_ARCH type: string + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -267,6 +270,7 @@ steps: VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} + VSCODE_BUILD_ESM: ${{ parameters.VSCODE_BUILD_ESM }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 0c4f98aa511..b0e495b7b73 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -100,6 +100,10 @@ parameters: displayName: "Skip tests" type: boolean default: false + - name: VSCODE_BUILD_ESM # TODO@bpasero TODO@esm remove me once ESM is shipped + displayName: "️❗ Build as ESM (!FOR TESTING ONLY!) ️❗" + type: boolean + default: false variables: - name: VSCODE_PRIVATE_BUILD @@ -110,6 +114,8 @@ variables: value: ${{ parameters.CARGO_REGISTRY }} - name: VSCODE_QUALITY value: ${{ parameters.VSCODE_QUALITY }} + - name: VSCODE_BUILD_ESM + value: ${{ parameters.VSCODE_BUILD_ESM }} - name: VSCODE_BUILD_STAGE_WINDOWS value: ${{ or(eq(parameters.VSCODE_BUILD_WIN32, true), eq(parameters.VSCODE_BUILD_WIN32_ARM64, true)) }} - name: VSCODE_BUILD_STAGE_LINUX @@ -148,6 +154,8 @@ variables: value: microsoft/vscode-distro - name: skipComponentGovernanceDetection value: true + - name: ComponentDetection.Timeout + value: 600 - name: Codeql.SkipTaskAutoInjection value: true - name: ARTIFACT_PREFIX @@ -167,7 +175,7 @@ resources: ref: refs/tags/release extends: - template: v1/1ES.Unofficial.PipelineTemplate.yml@1esPipelines + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: sdl: tsa: @@ -182,9 +190,10 @@ extends: validateToolOutput: None allTools: true codeql: + runSourceLanguagesInSourceAnalysis: true compiled: enabled: false - runSourceLanguagesInSourceAnalysis: true + 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: @@ -215,6 +224,7 @@ extends: - template: build/azure-pipelines/product-compile.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} - ${{ 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_ALPINE, true),eq(parameters.VSCODE_BUILD_ALPINE_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 @@ -316,17 +326,21 @@ extends: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} VSCODE_BUILD_WIN32_ARM64: ${{ parameters.VSCODE_BUILD_WIN32_ARM64 }} - - stage: CustomSDL - dependsOn: [] - pool: - name: 1es-windows-2019-x64 - os: windows - jobs: - - job: WindowsSDL - variables: - - group: 'API Scan' - steps: - - template: build/azure-pipelines/sdl-scan.yml@self + - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false)) }}: + - stage: CustomSDL + dependsOn: [] + pool: + name: 1es-windows-2019-x64 + os: windows + jobs: + - job: WindowsSDL + variables: + - group: 'API Scan' + 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 @@ -348,6 +362,7 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true @@ -362,6 +377,7 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -376,6 +392,7 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -391,6 +408,7 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_ARCH: x64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -414,6 +432,7 @@ extends: - template: build/azure-pipelines/win32/product-build-win32.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_ARCH: arm64 VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false @@ -442,6 +461,7 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false @@ -457,6 +477,7 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true @@ -472,6 +493,7 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -489,6 +511,7 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -514,6 +537,7 @@ extends: parameters: VSCODE_ARCH: armhf VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -529,6 +553,7 @@ extends: parameters: VSCODE_ARCH: arm64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -553,6 +578,7 @@ extends: parameters: VSCODE_ARCH: x64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARMHF_LEGACY_SERVER, true) }}: @@ -565,6 +591,7 @@ extends: parameters: VSCODE_ARCH: armhf VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_RUN_INTEGRATION_TESTS: false - ${{ if eq(parameters.VSCODE_BUILD_LINUX_ARM64_LEGACY_SERVER, true) }}: @@ -577,6 +604,7 @@ extends: parameters: VSCODE_ARCH: arm64 VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_RUN_INTEGRATION_TESTS: false - ${{ if and(eq(variables['VSCODE_CIBUILD'], false), eq(parameters.VSCODE_COMPILE_ONLY, false), eq(variables['VSCODE_BUILD_STAGE_ALPINE'], true)) }}: @@ -629,6 +657,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: true VSCODE_RUN_INTEGRATION_TESTS: false @@ -642,6 +671,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: true @@ -655,6 +685,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -669,6 +700,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false @@ -683,6 +715,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} VSCODE_RUN_INTEGRATION_TESTS: ${{ eq(parameters.VSCODE_STEP_ON_IT, false) }} @@ -714,6 +747,7 @@ extends: - template: build/azure-pipelines/darwin/product-build-darwin.yml@self parameters: VSCODE_QUALITY: ${{ variables.VSCODE_QUALITY }} + VSCODE_BUILD_ESM: ${{ variables.VSCODE_BUILD_ESM }} VSCODE_CIBUILD: ${{ variables.VSCODE_CIBUILD }} VSCODE_RUN_UNIT_TESTS: false VSCODE_RUN_INTEGRATION_TESTS: false diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml index 9a3748ed6fc..46b5dde2492 100644 --- a/build/azure-pipelines/product-compile.yml +++ b/build/azure-pipelines/product-compile.yml @@ -1,6 +1,9 @@ parameters: - name: VSCODE_QUALITY type: string + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - task: NodeTool@0 @@ -98,6 +101,10 @@ steps: - script: node build/azure-pipelines/distro/mixin-quality displayName: Mixin distro quality + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - script: node migrate.mjs --disable-watch + displayName: Migrate to ESM + - template: common/install-builtin-extensions.yml@self - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: diff --git a/build/azure-pipelines/win32/product-build-win32-test.yml b/build/azure-pipelines/win32/product-build-win32-test.yml index c9b2d6cfa61..fb3f3f4d73b 100644 --- a/build/azure-pipelines/win32/product-build-win32-test.yml +++ b/build/azure-pipelines/win32/product-build-win32-test.yml @@ -12,6 +12,9 @@ parameters: - name: PUBLISH_TASK_NAME type: string default: PublishPipelineArtifact@0 + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - powershell: yarn npm-run-all -lp "electron $(VSCODE_ARCH)" "playwright-install" @@ -22,30 +25,48 @@ steps: - ${{ if eq(parameters.VSCODE_RUN_UNIT_TESTS, true) }}: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: .\scripts\test.bat --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - - powershell: yarn test-node - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - powershell: node test/unit/browser/index.js --sequential --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - powershell: .\scripts\test-esm.bat --tfs "Unit Tests" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - powershell: yarn test-node-esm + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - powershell: node test/unit/browser/index.esm.js --sequential --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - powershell: .\scripts\test.bat --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - powershell: yarn test-node + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - powershell: node test/unit/browser/index.js --sequential --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: .\scripts\test.bat --build --tfs "Unit Tests" - displayName: Run unit tests (Electron) - timeoutInMinutes: 15 - - - powershell: yarn test-node --build - displayName: Run unit tests (node.js) - timeoutInMinutes: 15 - - - powershell: yarn test-browser-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" - displayName: Run unit tests (Browser, Chromium) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - powershell: .\scripts\test-esm.bat --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) [ESM] + timeoutInMinutes: 15 + - script: yarn test-node-esm --build + displayName: Run unit tests (node.js) [ESM] + timeoutInMinutes: 15 + - powershell: yarn test-browser-esm-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - powershell: .\scripts\test.bat --build --tfs "Unit Tests" + displayName: Run unit tests (Electron) + timeoutInMinutes: 15 + - powershell: yarn test-node --build + displayName: Run unit tests (node.js) + timeoutInMinutes: 15 + - powershell: yarn test-browser-no-install --sequential --build --browser chromium --tfs "Browser Unit Tests" + displayName: Run unit tests (Browser, Chromium) + timeoutInMinutes: 20 - ${{ if eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true) }}: - powershell: | @@ -77,9 +98,14 @@ steps: condition: succeededOrFailed() - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: .\scripts\test-integration.bat --tfs "Integration Tests" - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - powershell: .\scripts\test-integration-esm.bat --tfs "Integration Tests" + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - powershell: .\scripts\test-integration.bat --tfs "Integration Tests" + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - powershell: .\scripts\test-web-integration.bat --browser firefox displayName: Run integration tests (Browser, Firefox) @@ -90,20 +116,36 @@ steps: timeoutInMinutes: 20 - ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: - - powershell: | - # Figure out the full absolute path of the product we just built - # including the remote server and configure the integration tests - # to run with these builds instead of running out of sources. - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" - $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json - $AppNameShort = $AppProductJson.nameShort - $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" - $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" - exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } - displayName: Run integration tests (Electron) - timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, true) }}: + - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" + exec { .\scripts\test-integration-esm.bat --build --tfs "Integration Tests" } + displayName: Run integration tests (Electron) [ESM] + timeoutInMinutes: 20 + - ${{ if eq(parameters.VSCODE_BUILD_ESM, false) }}: + - powershell: | + # Figure out the full absolute path of the product we just built + # including the remote server and configure the integration tests + # to run with these builds instead of running out of sources. + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $AppRoot = "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" + $AppProductJson = Get-Content -Raw -Path "$AppRoot\resources\app\product.json" | ConvertFrom-Json + $AppNameShort = $AppProductJson.nameShort + $env:INTEGRATION_TEST_ELECTRON_PATH = "$AppRoot\$AppNameShort.exe" + $env:VSCODE_REMOTE_SERVER_PATH = "$(agent.builddirectory)\vscode-server-win32-$(VSCODE_ARCH)" + exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } + displayName: Run integration tests (Electron) + timeoutInMinutes: 20 - powershell: | . build/azure-pipelines/win32/exec.ps1 diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index d3827b930f8..a67e0ccf4e3 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -11,6 +11,9 @@ parameters: type: boolean - name: VSCODE_RUN_SMOKE_TESTS type: boolean + - name: VSCODE_BUILD_ESM + type: boolean + default: false steps: - ${{ if eq(parameters.VSCODE_QUALITY, 'oss') }}: @@ -160,7 +163,6 @@ steps: env: GITHUB_TOKEN: "$(github-distro-mixin-password)" displayName: Build server - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -171,7 +173,6 @@ steps: env: GITHUB_TOKEN: "$(github-distro-mixin-password)" displayName: Build server (web) - condition: and(succeeded(), ne(variables['VSCODE_ARCH'], 'arm64')) - ${{ if or(eq(parameters.VSCODE_RUN_UNIT_TESTS, true), eq(parameters.VSCODE_RUN_INTEGRATION_TESTS, true), eq(parameters.VSCODE_RUN_SMOKE_TESTS, true)) }}: - template: product-build-win32-test.yml@self @@ -181,6 +182,7 @@ steps: VSCODE_RUN_UNIT_TESTS: ${{ parameters.VSCODE_RUN_UNIT_TESTS }} VSCODE_RUN_INTEGRATION_TESTS: ${{ parameters.VSCODE_RUN_INTEGRATION_TESTS }} VSCODE_RUN_SMOKE_TESTS: ${{ parameters.VSCODE_RUN_SMOKE_TESTS }} + VSCODE_BUILD_ESM: ${{ parameters.VSCODE_BUILD_ESM }} ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}: PUBLISH_TASK_NAME: 1ES.PublishPipelineArtifact@1 @@ -312,7 +314,7 @@ steps: sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH) sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Server" sbomPackageVersion: $(Build.SourceVersion) - condition: and(succeededOrFailed(), ne(variables['SERVER_PATH'], ''), ne(variables['VSCODE_ARCH'], 'arm64')) + condition: and(succeededOrFailed(), ne(variables['SERVER_PATH'], '')) displayName: Publish server archive - task: 1ES.PublishPipelineArtifact@1 @@ -322,7 +324,7 @@ steps: sbomBuildDropPath: $(Agent.BuildDirectory)/vscode-server-win32-$(VSCODE_ARCH)-web sbomPackageName: "VS Code Windows $(VSCODE_ARCH) Web" sbomPackageVersion: $(Build.SourceVersion) - condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], ''), ne(variables['VSCODE_ARCH'], 'arm64')) + condition: and(succeededOrFailed(), ne(variables['WEB_PATH'], '')) displayName: Publish web server archive - task: 1ES.PublishPipelineArtifact@1 diff --git a/build/azure-pipelines/sdl-scan.yml b/build/azure-pipelines/win32/sdl-scan-win32.yml similarity index 60% rename from build/azure-pipelines/sdl-scan.yml rename to build/azure-pipelines/win32/sdl-scan-win32.yml index af20a305d9c..81c0258f4ee 100644 --- a/build/azure-pipelines/sdl-scan.yml +++ b/build/azure-pipelines/win32/sdl-scan-win32.yml @@ -1,14 +1,8 @@ parameters: - - name: NPM_REGISTRY - displayName: "Custom NPM Registry" - type: string - default: "https://pkgs.dev.azure.com/monacotools/Monaco/_packaging/vscode/npm/registry/" - - name: NPM_ARCH - type: string - default: x64 - name: VSCODE_ARCH type: string - default: x64 + - name: VSCODE_QUALITY + type: string steps: - task: NodeTool@0 @@ -17,7 +11,12 @@ steps: versionFilePath: .nvmrc nodejsMirror: https://github.com/joaomoreno/node-mirror/releases/download - - template: ./distro/download-distro.yml + - task: UsePythonVersion@0 + inputs: + versionSpec: "3.x" + addToPath: true + + - template: ../distro/download-distro.yml@self - task: AzureKeyVault@1 displayName: "Azure Key Vault: Get Secrets" @@ -26,40 +25,34 @@ steps: KeyVaultName: vscode-build-secrets SecretsFilter: "github-distro-mixin-password" + - powershell: node build/setup-npm-registry.js $env:NPM_REGISTRY + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) + displayName: Setup NPM Registry + - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - exec { npm config set registry "${{ parameters.NPM_REGISTRY }}" --location=project } + exec { npm config set registry "$env:NPM_REGISTRY" --location=project } # npm >v7 deprecated the `always-auth` config option, refs npm/cli@72a7eeb # following is a workaround for yarn to send authorization header # for GET requests to the registry. exec { Add-Content -Path .npmrc -Value "always-auth=true" } - exec { yarn config set registry "${{ parameters.NPM_REGISTRY }}" } - condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne('${{ parameters.NPM_REGISTRY }}', 'none')) + exec { yarn config set registry "$env:NPM_REGISTRY" } + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) displayName: Setup NPM & Yarn - task: npmAuthenticate@0 inputs: workingFile: .npmrc - condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne('${{ parameters.NPM_REGISTRY }}', 'none')) + condition: and(succeeded(), ne(variables['NPM_REGISTRY'], 'none')) displayName: Setup NPM Authentication - - powershell: | - . build/azure-pipelines/win32/exec.ps1 - $ErrorActionPreference = "Stop" - exec { node build/setup-npm-registry.js "${{ parameters.NPM_REGISTRY }}" } - condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'), ne('${{ parameters.NPM_REGISTRY }}', 'none')) - displayName: Setup NPM Registry - - pwsh: | $includes = @' { 'target_defaults': { 'conditions': [ ['OS=="win"', { - 'msvs_configuration_attributes': { - 'SpectreMitigation': 'Spectre' - }, 'msvs_settings': { 'VCCLCompilerTool': { 'AdditionalOptions': [ @@ -91,9 +84,11 @@ steps: $ErrorActionPreference = "Stop" retry { exec { yarn --frozen-lockfile --check-files } } env: + npm_config_arch: ${{ parameters.VSCODE_ARCH }} + CHILD_CONCURRENCY: 1 + ELECTRON_SKIP_BINARY_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 GITHUB_TOKEN: "$(github-distro-mixin-password)" - CHILD_CONCURRENCY: 1 displayName: Install dependencies - script: node build/azure-pipelines/distro/mixin-npm @@ -102,46 +97,62 @@ steps: - script: node build/azure-pipelines/distro/mixin-quality displayName: Mixin distro quality env: - VSCODE_QUALITY: stable + VSCODE_QUALITY: ${{ parameters.VSCODE_QUALITY }} - powershell: yarn compile displayName: Compile + - powershell: | + Get-ChildItem '$(Build.SourcesDirectory)' -Recurse -Filter "*.exe" + Get-ChildItem '$(Build.SourcesDirectory)' -Recurse -Filter "*.dll" + Get-ChildItem '$(Build.SourcesDirectory)' -Recurse -Filter "*.node" + Get-ChildItem '$(Build.SourcesDirectory)' -Recurse -Filter "*.pdb" + displayName: List files + - powershell: yarn gulp "vscode-symbols-win32-${{ parameters.VSCODE_ARCH }}" env: GITHUB_TOKEN: "$(github-distro-mixin-password)" displayName: Download Symbols + - powershell: | + Get-ChildItem '$(Agent.BuildDirectory)\scanbin' -Recurse -Filter "*.exe" + Get-ChildItem '$(Agent.BuildDirectory)\scanbin' -Recurse -Filter "*.dll" + Get-ChildItem '$(Agent.BuildDirectory)\scanbin' -Recurse -Filter "*.node" + Get-ChildItem '$(Agent.BuildDirectory)\scanbin' -Recurse -Filter "*.pdb" + displayName: List files again + - task: BinSkim@4 inputs: InputType: "Basic" Function: "analyze" TargetPattern: "guardianGlob" AnalyzeIgnorePdbLoadError: true - AnalyzeTargetGlob: '$(agent.builddirectory)\scanbin\**.dll;$(agent.builddirectory)\scanbin\**.exe;$(agent.builddirectory)\scanbin\**.node' - AnalyzeLocalSymbolDirectories: '$(agent.builddirectory)\scanbin\VSCode-win32-${{ parameters.VSCODE_ARCH }}\pdb' + AnalyzeTargetGlob: '$(Agent.BuildDirectory)\scanbin\**.dll;$(Agent.BuildDirectory)\scanbin\**.exe;$(Agent.BuildDirectory)\scanbin\**.node' + AnalyzeLocalSymbolDirectories: '$(Agent.BuildDirectory)\scanbin\VSCode-win32-${{ parameters.VSCODE_ARCH }}\pdb' - task: CopyFiles@2 displayName: 'Collect Symbols for API Scan' inputs: SourceFolder: $(Agent.BuildDirectory) Contents: 'scanbin\**\*.pdb' - TargetFolder: '$(agent.builddirectory)\symbols' + TargetFolder: '$(Agent.BuildDirectory)\symbols' flattenFolders: true condition: succeeded() - # - task: APIScan@2 - # inputs: - # softwareFolder: $(agent.builddirectory)\scanbin - # softwareName: 'vscode-client' - # softwareVersionNum: '1' - # symbolsFolder: 'SRV*http://symweb;$(agent.builddirectory)\symbols' - # isLargeApp: false - # toolVersion: 'Latest' - # displayName: Run ApiScan - # condition: succeeded() - # env: - # AzureServicesAuthConnectionString: $(apiscan-connectionstring) + - task: APIScan@2 + inputs: + softwareFolder: $(Agent.BuildDirectory)\scanbin + softwareName: 'vscode-client' + softwareVersionNum: '1' + symbolsFolder: 'srv*https://symweb.azurefd.net;$(Agent.BuildDirectory)\symbols' + isLargeApp: false + toolVersion: 'Latest' + azureSubscription: 'vscode-apiscan' + displayName: Run ApiScan + condition: succeeded() + env: + AzureServicesAuthConnectionString: $(apiscan-connectionstring) + SYSTEM_ACCESSTOKEN: $(System.AccessToken) - task: PublishSecurityAnalysisLogs@3 inputs: diff --git a/build/buildfile.js b/build/buildfile.js new file mode 100644 index 00000000000..74ac8436ccf --- /dev/null +++ b/build/buildfile.js @@ -0,0 +1,120 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const { isESM } = require('./lib/esm'); + +/** + * @param {string} name + * @param {string[]=} exclude + * @returns {import('./lib/bundle').IEntryPoint} + */ +function createModuleDescription(name, exclude) { + + let excludes = ['vs/css']; + if (Array.isArray(exclude) && exclude.length > 0) { + excludes = excludes.concat(exclude); + } + + return { + name: name, + include: [], + exclude: excludes + }; +} + +/** + * @param {string} name + */ +function createEditorWorkerModuleDescription(name) { + const amdVariant = createModuleDescription(name, ['vs/base/common/worker/simpleWorker', 'vs/editor/common/services/editorSimpleWorker']); + amdVariant.target = 'amd'; + + const esmVariant = { ...amdVariant, dest: undefined }; + esmVariant.target = 'esm'; + esmVariant.name = `${esmVariant.name}.esm`; + + return [amdVariant, esmVariant]; +} + +// TODO@esm take the editor simple worker top level and rename away from "base" +exports.base = [ + { + name: 'vs/editor/common/services/editorSimpleWorker', + include: ['vs/base/common/worker/simpleWorker'], + exclude: [], + prepend: [ + { path: 'vs/loader.js' }, + { path: 'vs/base/worker/workerMain.js' } + ], + dest: 'vs/base/worker/workerMain.js', + target: 'amd' + }, + { + name: 'vs/editor/common/services/editorSimpleWorker.esm', + target: 'esm' + }, + { + name: 'vs/base/common/worker/simpleWorker', + exclude: [], + target: 'amd' + } +]; + +exports.workerExtensionHost = createEditorWorkerModuleDescription('vs/workbench/api/worker/extensionHostWorker'); +exports.workerNotebook = createEditorWorkerModuleDescription('vs/workbench/contrib/notebook/common/services/notebookSimpleWorker'); +exports.workerLanguageDetection = createEditorWorkerModuleDescription('vs/workbench/services/languageDetection/browser/languageDetectionSimpleWorker'); +exports.workerLocalFileSearch = createEditorWorkerModuleDescription('vs/workbench/services/search/worker/localFileSearch'); +exports.workerProfileAnalysis = createEditorWorkerModuleDescription('vs/platform/profiling/electron-sandbox/profileAnalysisWorker'); +exports.workerOutputLinks = createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'); +exports.workerBackgroundTokenization = createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'); + +exports.workbenchDesktop = function () { + return isESM() ? [ + createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'), + createModuleDescription('vs/platform/files/node/watcher/watcherMain'), + createModuleDescription('vs/platform/terminal/node/ptyHostMain'), + createModuleDescription('vs/workbench/api/node/extensionHostProcess'), + createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'), + createModuleDescription('vs/workbench/workbench.desktop.main') + ] : [ + ...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'), + ...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'), + createModuleDescription('vs/workbench/contrib/debug/node/telemetryApp'), + createModuleDescription('vs/platform/files/node/watcher/watcherMain'), + createModuleDescription('vs/platform/terminal/node/ptyHostMain'), + createModuleDescription('vs/workbench/api/node/extensionHostProcess'), + createModuleDescription('vs/workbench/contrib/issue/electron-sandbox/issueReporterMain'), + ]; +}; + +exports.workbenchWeb = function () { + return isESM() ? [ + createModuleDescription('vs/workbench/workbench.web.main') + ] : [ + ...createEditorWorkerModuleDescription('vs/workbench/contrib/output/common/outputLinkComputer'), + ...createEditorWorkerModuleDescription('vs/workbench/services/textMate/browser/backgroundTokenization/worker/textMateTokenizationWorker.worker'), + createModuleDescription('vs/code/browser/workbench/workbench', ['vs/workbench/workbench.web.main']) + ]; +}; + +exports.keyboardMaps = [ + createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux'), + createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin'), + createModuleDescription('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win') +]; + +exports.code = [ + createModuleDescription('vs/code/electron-main/main'), + createModuleDescription('vs/code/node/cli'), + createModuleDescription('vs/code/node/cliProcessMain', ['vs/code/node/cli']), + createModuleDescription('vs/code/node/sharedProcess/sharedProcessMain'), + createModuleDescription('vs/code/electron-sandbox/processExplorer/processExplorerMain') +]; + +exports.codeWeb = [ + createModuleDescription('vs/code/browser/workbench/workbench') +]; + +exports.entrypoint = createModuleDescription; diff --git a/build/checksums/electron.txt b/build/checksums/electron.txt index 52950abd800..aecf657e571 100644 --- a/build/checksums/electron.txt +++ b/build/checksums/electron.txt @@ -1,75 +1,75 @@ -cdf0522dacc5fdf75a9a4ca9a20f049793ef8bae2b04e37f02e8923fcecd4c76 *chromedriver-v30.1.2-darwin-arm64.zip -f739afd34c48aae18da1d9dffb2332f0c2b2e27ff2056ac619e0a8c9414618f0 *chromedriver-v30.1.2-darwin-x64.zip -c2a220a316c268984bb8135975f28adecc392cf5cd2244af8cc21d60018a6a10 *chromedriver-v30.1.2-linux-arm64.zip -fad358f076caff4eecc3d8b63cea2e109cc0ff8b4632bb4edd21a7c7721bc428 *chromedriver-v30.1.2-linux-armv7l.zip -addc230541e9ee44b311fba9e900c5cb7d8b4d64b79a6d5dae68a71ced1c4611 *chromedriver-v30.1.2-linux-x64.zip -e2d0876fac8af41e0dd9c1b14c5315b426c55217e54e2b4ca5e28faae1b19557 *chromedriver-v30.1.2-mas-arm64.zip -c705d0b74a4658c197a87ed1e9e2509e55186769376b40493ec68b7cbb36c312 *chromedriver-v30.1.2-mas-x64.zip -8bbf9ccb789b236dec3e871d2499c14926a4c2dd3c865f8c7316ba3aa5b3f58f *chromedriver-v30.1.2-win32-arm64.zip -75af4b07bbd3a8fd7e18d63eb936e11054d01b52d438e4f7b7c5e6b82a41dec3 *chromedriver-v30.1.2-win32-ia32.zip -2d306df2c66314be12df78b6139ebf2d616463efdf4017473330d87a61954c3a *chromedriver-v30.1.2-win32-x64.zip -1990fe83ca25b990773ce099b90fb804fc026c1398279731229ba37d02c23000 *electron-api.json -64360b0db764c1bf16a8ab810a25c03f68873691d2897b360281bc50a645b6bb *electron-v30.1.2-darwin-arm64-dsym-snapshot.zip -3192307419ee2bafc3c99c62d79dbd2e6cba5815ae245be994f0b1e1d7fedb46 *electron-v30.1.2-darwin-arm64-dsym.zip -823eadc46a498af7433dae2ace1c8f0b2b0c8cbf98204fed0fdce8110ddafbc1 *electron-v30.1.2-darwin-arm64-symbols.zip -3c651624b1605411e595a6e9f6e874effb947c80eda4b8d0bb7d2972ff6ff242 *electron-v30.1.2-darwin-arm64.zip -fa5cbbc3e7760907229fa0753c3faa2b43e09bcb987b6c3f693e0030aa65e62b *electron-v30.1.2-darwin-x64-dsym-snapshot.zip -d97087f4c7e41fd67b2f0f7aa623ccf1effdbb94133b883dbae1e4c42a576b03 *electron-v30.1.2-darwin-x64-dsym.zip -a129109ed6ca23f66d625ebff9e57be117bc0a32c4f4348e78c1ad7dd41c4189 *electron-v30.1.2-darwin-x64-symbols.zip -8645e10af9b047c765a6cc880f9fa53f266e618569eaf65c0ea9fa1058be20f7 *electron-v30.1.2-darwin-x64.zip -afa016399f57bbbb658238dd715ef2a66790602ff46514e9cd99f2e078789c7d *electron-v30.1.2-linux-arm64-debug.zip -aec05a3e46a83d7c3e502b04245d3d6d2db8d5789a4dcc991f7cf6e7e3cd7036 *electron-v30.1.2-linux-arm64-symbols.zip -953c51413abfd62efdba070f99c961202ce5ef5e77c5cee5eaaf097ac2f5bc9b *electron-v30.1.2-linux-arm64.zip -afa016399f57bbbb658238dd715ef2a66790602ff46514e9cd99f2e078789c7d *electron-v30.1.2-linux-armv7l-debug.zip -04a6851e218c9a6f70870a341beea1b194a94d2d78f3a283065a34654cce7e30 *electron-v30.1.2-linux-armv7l-symbols.zip -677d6b4e6721ffb27b0037628c235cd0a9f10104beabb2b6c67d4b0328a9d001 *electron-v30.1.2-linux-armv7l.zip -1b6d8926e2c7cacbb33e56259ebe908c52e2a6dbbe37f0def043121f228a3a37 *electron-v30.1.2-linux-x64-debug.zip -dc4b526b02ec028d20836ee4617335d0569170846959761c3e8dc615d668f596 *electron-v30.1.2-linux-x64-symbols.zip -724aeca4b2f428f544e9b7e5e52e2074458c2e198f588530819cd0318af8599d *electron-v30.1.2-linux-x64.zip -15b10a6cf6a1ea029792282088647abbf58b415fdb4dd004c2c67c4a8f216ef3 *electron-v30.1.2-mas-arm64-dsym-snapshot.zip -00dbfc36c8ff6ecfbb8b01b51fee41f876bf3456017a8cc694a0c56608061f5e *electron-v30.1.2-mas-arm64-dsym.zip -e402b68cad20ee60cce376dacf0e2e72f1fcd0b6359dda7789626dca4b101e8b *electron-v30.1.2-mas-arm64-symbols.zip -8e59fc7c6df96a029310d6f7769e0c76592dc746d31764b35460de129231d12b *electron-v30.1.2-mas-arm64.zip -e8bfe6b58d2767dd52a7668df380be9c786abed0b25d642bee70c278758d2e77 *electron-v30.1.2-mas-x64-dsym-snapshot.zip -418f32558f9a107ebc942666a6ca680874db8ed438ae3f0064255abe0f9ce77e *electron-v30.1.2-mas-x64-dsym.zip -6d05da37cb39c664a764c879216e762efdb66f97734e42bbaa8f115b11fd3c87 *electron-v30.1.2-mas-x64-symbols.zip -af7b85a28593227add7e595e01d570e19512b40a29599ec007ef7cd4b5a11435 *electron-v30.1.2-mas-x64.zip -580c9b9fee6bacfdc4d3a1118953ba0096bcc19d28b1d804d72d40c5caac8d81 *electron-v30.1.2-win32-arm64-pdb.zip -dbb0ce79933c3688b7fa2bf04ce083d6e8da0a8c07b5104f53805e2e92679cd4 *electron-v30.1.2-win32-arm64-symbols.zip -7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.1.2-win32-arm64-toolchain-profile.zip -1b9035b541999e0cedcfe3893bb3c1497435494279d599c4e9300fe204f4d560 *electron-v30.1.2-win32-arm64.zip -3cb6869a69d118488dc48ed573b3fc9445bea33cf0a04338ca1b8000b4eaf516 *electron-v30.1.2-win32-ia32-pdb.zip -3f353849ef21506d5ca7a2c26df84d7c744ef1795acd33307f501764dfbe9bc1 *electron-v30.1.2-win32-ia32-symbols.zip -7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.1.2-win32-ia32-toolchain-profile.zip -431aff46eca9ddb726af3c8d6f4bbb72158e5c872c1b8bee221b3df0a8e94947 *electron-v30.1.2-win32-ia32.zip -85428715d302d4c97e47ca0b6409497191846baccbc36debf895cde724f9445f *electron-v30.1.2-win32-x64-pdb.zip -a5156829bc0caab5c70e6cd352941b6fb7b1e396d7869298c1ceaa69d742e3dc *electron-v30.1.2-win32-x64-symbols.zip -7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.1.2-win32-x64-toolchain-profile.zip -d400ed1aca2b7b1093aee8b5a8544b112e9f81a570cf77f6bdfe019ceb003f7f *electron-v30.1.2-win32-x64.zip -3187cdd642b968e17a768a3fdaff44bedb69954be3d88e7ad55aac9787b70485 *electron.d.ts -4c8bd4215102f563cf0464ae4edd4022921c53e0ebd4bb6b6f7f7434d50081aa *ffmpeg-v30.1.2-darwin-arm64.zip -2b8c57755ccb64a64540433d3cfbfecd29d07e28bf23c5f08a2edd0e2333a645 *ffmpeg-v30.1.2-darwin-x64.zip -c6f69859dc2ca04daa7c218936e5bc044fc19582423db954c5e8664ce7f331df *ffmpeg-v30.1.2-linux-arm64.zip -12f760ce312e4ee98ddd9496600ca9a1468e28f0ed6d41c6b9284dec841f550f *ffmpeg-v30.1.2-linux-armv7l.zip -c7207cc057849033d550d6897a53f7abee455f31b8f571c3c57a01f2871ff5af *ffmpeg-v30.1.2-linux-x64.zip -447b19465677636261ce47cc256f221c660e66cd136b33c3c742b8d23481b924 *ffmpeg-v30.1.2-mas-arm64.zip -e44fcdb5d0e62d328c0bb5ebeed54f388b09591a33e4dc1698c421e4c9d881dc *ffmpeg-v30.1.2-mas-x64.zip -b470cc217c4f06b3fe4edf6695b4762e7c926d07c1f41c3cab0ddb1d71ce8ce4 *ffmpeg-v30.1.2-win32-arm64.zip -92f1743c16210a77d07e9553cf96ccfb4e6985cc50ee831b5b075589aa0ebb05 *ffmpeg-v30.1.2-win32-ia32.zip -b2fa79b739023651f0551ca06ac5da7b47acaaf8b09ccdedf7081fc3ea824a80 *ffmpeg-v30.1.2-win32-x64.zip -b2b562a45ae4a2d40bf039ed1c707a7875b9e893fc8c6a0044d536b0f9968629 *hunspell_dictionaries.zip -08da936356d1321eec550c30a9208750773d86e3be0b7fe4baf36c72a8609c20 *libcxx-objects-v30.1.2-linux-arm64.zip -8aa302ac17f6ac44f756cb9219f18d01d267d43f9af2dfd8d4626e9d01e584fa *libcxx-objects-v30.1.2-linux-armv7l.zip -1ab04d6cec407930a2051761e6114cb2cd6418e2103d32e835246d06c696b427 *libcxx-objects-v30.1.2-linux-x64.zip -4db17e017bdb818cca5d8e08a78fe54fb907c3cf05defd1b8f086b413075357a *libcxx_headers.zip -209f20bd3ee59fa7c85b0789d8e45168583407c9fb5bd2eba446c1e0796c4a7b *libcxxabi_headers.zip -4dcc59b7c66b9ccc881dbdfeba9de707f693fd839a8e764d34bb66dec7e3e63c *mksnapshot-v30.1.2-darwin-arm64.zip -582886552cbc227eb71f5047d00ac62baeb1912a52a8f5132953b94f54d41dd4 *mksnapshot-v30.1.2-darwin-x64.zip -639fde4957353d48be54b9075c0894b7529210f0bb3a2f9cad81ba2deb415080 *mksnapshot-v30.1.2-linux-arm64-x64.zip -1fec2ae49a9f03117a5e5b637866e5aa270da2fa3a007d0314c8a39ed392230f *mksnapshot-v30.1.2-linux-armv7l-x64.zip -494f86a178a2b14101c6deccf7c2ae88c690c7ce8445b63854a2e0525d69aaa0 *mksnapshot-v30.1.2-linux-x64.zip -bfbb90138b4df3f57fd9fe9cc05b6b8f9b3bf099b66d65215cc9434e2272b0d1 *mksnapshot-v30.1.2-mas-arm64.zip -d1a6a825628a141fdd73cf208180cc20af32b8e06aeb7f4d36566358cef40a90 *mksnapshot-v30.1.2-mas-x64.zip -fd523788a380990d589f9461f29a8878b63090146aa124f2debf3197af69929b *mksnapshot-v30.1.2-win32-arm64-x64.zip -69068d132cd511e33be9aff6dda5df74079c2003657cd89107d4eaaac7e4d997 *mksnapshot-v30.1.2-win32-ia32.zip -69bfab7461f83a256c0869e2781cca4f5a53f8b6a60d78617b79b8bfc0b554b6 *mksnapshot-v30.1.2-win32-x64.zip +3e432bd550279c2d58c6a02b0bda048fa2a9a89aef9752e22c39a518a83fe96f *chromedriver-v30.4.0-darwin-arm64.zip +4d38f40ec33955dd0aef5cc0053b2b07c4744abb9f2614a44780280c4678aca9 *chromedriver-v30.4.0-darwin-x64.zip +338f2a361448e78aa8c319cd582f2dd6d891d6c0c66b676c628e50511c27514f *chromedriver-v30.4.0-linux-arm64.zip +8cffae19618fe5f0eaff40378c40084e18f9747bbbe2d87390203a3012c98367 *chromedriver-v30.4.0-linux-armv7l.zip +7ff1b75defc522f327c0f1bf6f4d13938b041cf5de1d7417b9dc5d1e7026e93c *chromedriver-v30.4.0-linux-x64.zip +8e93b0892d7d01c38608fa7907f28da1da27de09bb382f261d81a676f8c2ba64 *chromedriver-v30.4.0-mas-arm64.zip +d306ef0bc651bef046b21ba2e4745e2768be9df1b6c2fc2e7b1a0368f7e10d76 *chromedriver-v30.4.0-mas-x64.zip +bb7c5db2a20f437e0b398846ecc8111e7e51e2021b78f60db021262daacf7d7c *chromedriver-v30.4.0-win32-arm64.zip +df4acaa6684e7db07468c6dc8102cb49746884e8db2b53648431b2b61e8debb2 *chromedriver-v30.4.0-win32-ia32.zip +7a207b29977e52ba052037f00f4ea6284177fdd93e0774dfc39e83ee5a86513d *chromedriver-v30.4.0-win32-x64.zip +8c876662fd46c37b2dd9487ea8e62fde3f20a729dc95e42f12f7db4986138edc *electron-api.json +a36786c7d4e30887a6aa1f2adbc23e721266a31ffe84191bf4caddb731cfb973 *electron-v30.4.0-darwin-arm64-dsym-snapshot.zip +e5edcad107307e97bdd6f69ccab0368df4c3270213f2f42f259f3723d24ca611 *electron-v30.4.0-darwin-arm64-dsym.zip +cc522e772a1d80f7ec73ce2077dae93de76cd4f6767c467b6a8e01e4a252f15f *electron-v30.4.0-darwin-arm64-symbols.zip +2238c45a85b2c78aed00aeaf15bbfa2f64b4d13e48cc6b9bc330f24c4d214595 *electron-v30.4.0-darwin-arm64.zip +48c3197fc36f5ef64eaa913a0a769d2b2d4b79c94e61991ca73e8be2b24bf997 *electron-v30.4.0-darwin-x64-dsym-snapshot.zip +9b669dc060695e5495573cce7b7916bdadd980d523772fbbf57fd1811bb4feca *electron-v30.4.0-darwin-x64-dsym.zip +0acd5b74cbb1719a89a310fb42f5ab4282711bb0ccf4e8b242d9c24c8ecc7136 *electron-v30.4.0-darwin-x64-symbols.zip +6e633bf87be9f8bf46dff9733cfd0d611e018ae5df75f30735747721f91fcf43 *electron-v30.4.0-darwin-x64.zip +5bc27ceae706116a14fa24da3cda32f00893dd3f51ae2c2d58c4c08f26ce2ac2 *electron-v30.4.0-linux-arm64-debug.zip +d13970ef6f4ad30dd8268563ed0b768f703d6e4ea1389ee36b8e7eb407b40523 *electron-v30.4.0-linux-arm64-symbols.zip +aa422122373b84f4eb8ce937937b1b6fe8fb3975c3edafb9df85f7fba449afd4 *electron-v30.4.0-linux-arm64.zip +5bc27ceae706116a14fa24da3cda32f00893dd3f51ae2c2d58c4c08f26ce2ac2 *electron-v30.4.0-linux-armv7l-debug.zip +645af6535a3956e263d8ff586bfb45c5d16ec4c07add406e7c2a767eec070e8e *electron-v30.4.0-linux-armv7l-symbols.zip +3643857e1eec3037ad6f07e755bffc64f033a7196307ff0386bf67c9cc3ec31e *electron-v30.4.0-linux-armv7l.zip +0f099b597830fd990bac82fbe976720d5610450133dff880b570cbe1ef793742 *electron-v30.4.0-linux-x64-debug.zip +084566b78797502ad164832e49690d8845c53a8becb28085f271ab1a9fe20942 *electron-v30.4.0-linux-x64-symbols.zip +b365aac23c61dc0b18002c60937c4842e814cbe6d8e6a34e4dc211774ebaec01 *electron-v30.4.0-linux-x64.zip +b050b4de0fda4c2fa4ceeb0ecaf452cc426a9b03a9e286686d2167c7ded252f4 *electron-v30.4.0-mas-arm64-dsym-snapshot.zip +1e9c3f820e809fc2e05434d54862c7309dd04b74406869e06edb1e07faa3e40f *electron-v30.4.0-mas-arm64-dsym.zip +9b4112c73606d1a0393320178a3d0f172671ec211fe69b2106ad9b04b55b3538 *electron-v30.4.0-mas-arm64-symbols.zip +10ac65b581c2941fd05b2804055be2eed8d69de4c82b90f7357a3989d8276c9f *electron-v30.4.0-mas-arm64.zip +9e4cba132474d82894541ab33d02b28894f0452f4c6808e2428878d0b6a55aac *electron-v30.4.0-mas-x64-dsym-snapshot.zip +33c9c13a8a33ab292db5f14b1d8af1fa7967601badf505a06972fd3cdc9cb6bb *electron-v30.4.0-mas-x64-dsym.zip +1e8871c34294912bc562861226742dcd2de073ae2dc3fef8065fe86550265bca *electron-v30.4.0-mas-x64-symbols.zip +055bea26dfd9fa86838e25b77e29fec3967ed21020ce1362ff683be07ac90c45 *electron-v30.4.0-mas-x64.zip +1fd654358ad895fce4806fcd39be848deeccd20f767e96006ebb5c88ca973d92 *electron-v30.4.0-win32-arm64-pdb.zip +5cf51db3ece15f155afc066230f844bf7825fe912f0f479b8cf9eb47e46a2278 *electron-v30.4.0-win32-arm64-symbols.zip +7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.4.0-win32-arm64-toolchain-profile.zip +51bc3a21faefe99ccc8e8670dccf2320249af5c185728a31d907a18092542d73 *electron-v30.4.0-win32-arm64.zip +b4a539c7dbad3db544d7709faaf357d55d7f3349bfd4d42c884b0608725b526d *electron-v30.4.0-win32-ia32-pdb.zip +ddb355e3e45978eee33c679c42781587533b934f3e98374057d2b0c212062915 *electron-v30.4.0-win32-ia32-symbols.zip +7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.4.0-win32-ia32-toolchain-profile.zip +7260c9f533d5fa0c543d34593bb1a8bc4904943ca872afc5246e15da6f00b43a *electron-v30.4.0-win32-ia32.zip +2d0d5631158971e0fac9bb7c427c5361177c7e967cca41940ad18183d95c3e23 *electron-v30.4.0-win32-x64-pdb.zip +0ea8c0b8734bd45cb04ae83390bd7efee407ed6bb30dbaa1030e1a1f03a0f025 *electron-v30.4.0-win32-x64-symbols.zip +7351fa5cb892853a7d4b67d8858d0f9cc6506c554a2e42c9ad7e8d5e29ae2743 *electron-v30.4.0-win32-x64-toolchain-profile.zip +9dcf4b5bbdb6c672ba1b3812d4b642999faf4b6f4e2a4e4af314ba61596a62dc *electron-v30.4.0-win32-x64.zip +c524777653f0b3ba58da6c1e97aa5a3a172caf68d9b24a7d33f733b36c281ce8 *electron.d.ts +c1586ee3f3960943dfa1c1a3da2ebc327afd95c3c7a160b0646730fbc78731bb *ffmpeg-v30.4.0-darwin-arm64.zip +7f76a792c8f9ee9611f966956b4b70017253f9357ec73806d35c568808eec470 *ffmpeg-v30.4.0-darwin-x64.zip +5160348bcae6cb4fce20905338a903475c2eb52511370b44bdfeafef3cbeab6c *ffmpeg-v30.4.0-linux-arm64.zip +4f7583513d48b48c44a2cbc4430cbc9a33d8f9728622166db688e3de61190821 *ffmpeg-v30.4.0-linux-armv7l.zip +4f62d246a2ccb904e9f03bdc65fd5806edd69b95099fa2dcba4f148d44ea1bce *ffmpeg-v30.4.0-linux-x64.zip +c1586ee3f3960943dfa1c1a3da2ebc327afd95c3c7a160b0646730fbc78731bb *ffmpeg-v30.4.0-mas-arm64.zip +7f76a792c8f9ee9611f966956b4b70017253f9357ec73806d35c568808eec470 *ffmpeg-v30.4.0-mas-x64.zip +26b82e5943d09eb0765804df27182cd45c45e63e82fe95d60a5a78611d85a926 *ffmpeg-v30.4.0-win32-arm64.zip +ea688b108cb545bd436621c8d1279696ac6cb0b041d1d3d322dba06f8dd0f295 *ffmpeg-v30.4.0-win32-ia32.zip +733a522d2095964ff3796f3301591b7aa9cf1ba8dcc545d1928745022ef99e6a *ffmpeg-v30.4.0-win32-x64.zip +0b82c8db956264c1be4006eff3908b51ae8e48a17176fe61fa86d8ca8c103bf5 *hunspell_dictionaries.zip +27d5d6d82bd5703342e6a3804ff3c032433cda833ad3881f263035b23193ace9 *libcxx-objects-v30.4.0-linux-arm64.zip +babe51c929cc77907fdb5af11781938bab4b9f31642a0220b4ce4a35cfb904ff *libcxx-objects-v30.4.0-linux-armv7l.zip +e6e13dd7c493841c3ab406b147d021b4e5a379e286767c1459d23bd9581c10c9 *libcxx-objects-v30.4.0-linux-x64.zip +c9ba1b8c0e971cf477f7c0120436cc45a02b72908a41c82cd809ec8014b81e32 *libcxx_headers.zip +2c4c140bfeb235584f8f7c699d0d95b16ddb959484923aaa59eeb3310dbc161a *libcxxabi_headers.zip +0cee8848525e0d633d3ccf599d03ac05be6e0bc014b5a77ddce99c3a50941feb *mksnapshot-v30.4.0-darwin-arm64.zip +0c491f602cfc6fbd81b8b771d3fa28ec1eb77c23c7636479a158265dd7d59977 *mksnapshot-v30.4.0-darwin-x64.zip +6ea645627b0a0cab88cda80a2fa4d399a491bc5f0d0ff1d007f6dd28728d4592 *mksnapshot-v30.4.0-linux-arm64-x64.zip +6b33e8bc53281710d9754e3ea88a8c025649f3d7c499e9b8693183bd2b76ea8d *mksnapshot-v30.4.0-linux-armv7l-x64.zip +092afde6a2ab8ac922524a02b30343cd11f96c01405814019797bf38fa8c634b *mksnapshot-v30.4.0-linux-x64.zip +dada39480526a46992f2ff0ad8ea72a26565384e9976497867a6c4776705e49f *mksnapshot-v30.4.0-mas-arm64.zip +4082f5b379b788d300b2a7fc7c84deee80ebc61a34b534c795c1b4594c3f0d1a *mksnapshot-v30.4.0-mas-x64.zip +01a5e83fe293dd2c52e1d5cc79450fbfc1dfa1e4988146f94bfbf9a9e24cb9d7 *mksnapshot-v30.4.0-win32-arm64-x64.zip +0bccaa2779f8ce98bd4a2a66be082bcd3c34484aad8000c08de0fed5acb8ad88 *mksnapshot-v30.4.0-win32-ia32.zip +439c7f5b9fdd0ea19ee95f724773cda42382b27a31494ae8f2aca5c2ec043ec7 *mksnapshot-v30.4.0-win32-x64.zip diff --git a/build/checksums/nodejs.txt b/build/checksums/nodejs.txt index 877d8afe243..23a56cdb23b 100644 --- a/build/checksums/nodejs.txt +++ b/build/checksums/nodejs.txt @@ -1,7 +1,7 @@ -d2148d79e9ff04d2982d00faeae942ceba488ca327a91065e528235167b9e9d6 node-v20.14.0-darwin-arm64.tar.gz -1dcc18a199cb5f46d43ed1c3c61b87a247d1a1a11dd6b32a36a9c46ac1088f86 node-v20.14.0-darwin-x64.tar.gz -d63e83fca4f81801396620c46a42892a2ef26e21a4508f68de373e61a12bd9c5 node-v20.14.0-linux-arm64.tar.gz -af45ea0d09e55a4f05c0190636532bdf9f70b2eaf0a1c4d7594207cf21284df0 node-v20.14.0-linux-armv7l.tar.gz -5b9bf40cfc7c21de14a1b4c367650e3c96eb101156bf9368ffc2f947414b6581 node-v20.14.0-linux-x64.tar.gz -a6ec02119098cf92592539e06289953c4365be20ab15d4ad264669f931000b0c win-arm64/node.exe -8f45741ec6ba07be8d199c0cebc838a58c0430c9228dbe50f8ac5d4859e58bae win-x64/node.exe +4743bc042f90ba5d9edf09403207290a9cdd2f6061bdccf7caaa0bbfd49f343e node-v20.15.1-darwin-arm64.tar.gz +f5379772ffae1404cfd1fcc8cf0c6c5971306b8fb2090d348019047306de39dc node-v20.15.1-darwin-x64.tar.gz +8554c91ccd32782351035d3a9b168ad01c6922480800a21870fc5d6d86c2bb70 node-v20.15.1-linux-arm64.tar.gz +2c16717da7d2d7b00f6af146cdf436a0297cbcee52c85b754e4c9ed7cee34b51 node-v20.15.1-linux-armv7l.tar.gz +a9db028c0a1c63e3aa0d97de24b0966bc507d8239b3aedc4e752eea6b0580665 node-v20.15.1-linux-x64.tar.gz +8e3f84e8ec7e41f98a048eb0c1365cfe54426a556ead98c4803df45d29e0335d win-arm64/node.exe +229fb64aeb10d3cc18eaaa2f5a4c3f1c81792dd3647c5c4350e142db528d0f89 win-x64/node.exe diff --git a/build/darwin/create-universal-app.js b/build/darwin/create-universal-app.js index 16c2b955dfb..3ac0e9d0de0 100644 --- a/build/darwin/create-universal-app.js +++ b/build/darwin/create-universal-app.js @@ -3,51 +3,16 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; - return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; Object.defineProperty(exports, "__esModule", { value: true }); -var path = require("path"); -var fs = require("fs"); -var minimatch = require("minimatch"); -var vscode_universal_bundler_1 = require("vscode-universal-bundler"); -var cross_spawn_promise_1 = require("@malept/cross-spawn-promise"); -var root = path.dirname(path.dirname(__dirname)); +const path = require("path"); +const fs = require("fs"); +const minimatch = require("minimatch"); +const vscode_universal_bundler_1 = require("vscode-universal-bundler"); +const cross_spawn_promise_1 = require("@malept/cross-spawn-promise"); +const esm_1 = require("../lib/esm"); +const root = path.dirname(path.dirname(__dirname)); // --- Start Positron --- -var os = require("os"); +const os = require("os"); // The merging procedure will fail if: // // (a) It finds x64 files that don't have an arm64 equivalent. For instance the @@ -67,11 +32,11 @@ var os = require("os"); // The files to stash away are determined with minimatch patterns. Folders are // excluded from matches, so to match a whole folder use `myfolder/**`. // -var stashPatterns = [ +const stashPatterns = [ // Exclusions from ZeroMQ node module - '**/electron.napi.node', - '**/node.napi.node', - '**/node.napi.glibc.node', + '**/electron.napi.node', // ZeroMQ Electron architecture-specific pre-built binary + '**/node.napi.node', // ZeroMQ Electron architecture-specific pre-built binary + '**/node.napi.glibc.node', // ZeroMQ Electron architecture-specific pre-built binary // Exclusions from remote-ssh '**/cpufeatures.node', '**/sshcrypto.node', @@ -79,16 +44,16 @@ var stashPatterns = [ '**/HTML.icns', '**/html.icns', // Exclusions from Python language pack (positron-python) - '**/pydevd/**', + '**/pydevd/**', // Cython pre-built binaries for Python debugging // Exclusions from R language pack (positron-r) - '**/ark', + '**/ark', // Compiled R kernel and LSP // Exclusions from Quarto '**/quarto/bin/tools/**', ]; // Some generated files may end up being different in both distributions. // `reconciliationFiles` contains relative paths of files that should be copied // from the x64 bundle to the arm64 one so they don't cause a mismatch error. -var reconciliationFiles = [ +const reconciliationFiles = [ 'Contents/Resources/app/product.json', // Definitions of localized strings 'Contents/Resources/app/out/nls.messages.json', @@ -110,11 +75,10 @@ var reconciliationFiles = [ 'Contents/Resources/app/out/vs/workbench/workbench.desktop.main.js', ]; function readFiles(dir) { - var files = []; - var entries = fs.readdirSync(dir, { withFileTypes: true }); - for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) { - var entry = entries_1[_i]; - var fullPath = path.join(dir, entry.name); + let files = []; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); // Recurse into directories and only return files if (entry.isDirectory()) { files = files.concat(readFiles(fullPath)); @@ -126,28 +90,27 @@ function readFiles(dir) { return files; } function ensureDir(file) { - var dir = path.dirname(file); + const dir = path.dirname(file); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } return dir; } function stashFiles(stash, x64Path, arm64Path) { - var x64Stash = path.join(stash, 'x64'); - var arm64Stash = path.join(stash, 'arm64'); + const x64Stash = path.join(stash, 'x64'); + const arm64Stash = path.join(stash, 'arm64'); fs.mkdirSync(x64Stash); fs.mkdirSync(arm64Stash); - var matches = readFiles(x64Path). - filter(function (file) { return stashPatterns.some(function (pat) { return minimatch(file, pat); }); }); - for (var _i = 0, matches_1 = matches; _i < matches_1.length; _i++) { - var x64Source = matches_1[_i]; - var rel = path.relative(x64Path, x64Source); - var arm64Source = path.join(arm64Path, rel); + const matches = readFiles(x64Path). + filter((file) => stashPatterns.some(pat => minimatch(file, pat))); + for (const x64Source of matches) { + const rel = path.relative(x64Path, x64Source); + const arm64Source = path.join(arm64Path, rel); if (!fs.existsSync(arm64Source)) { - throw new Error("Cannot find '".concat(rel, "' in arm64 source")); + throw new Error(`Cannot find '${rel}' in arm64 source`); } - var x64Dest = path.join(x64Stash, rel); - var arm64Dest = path.join(arm64Stash, rel); + const x64Dest = path.join(x64Stash, rel); + const arm64Dest = path.join(arm64Stash, rel); ensureDir(x64Dest); ensureDir(arm64Dest); fs.renameSync(x64Source, x64Dest); @@ -156,113 +119,88 @@ function stashFiles(stash, x64Path, arm64Path) { } // Copy files to reconcile from the x64 build to the arm64 one function reconcileFiles(x64Path, arm64Path) { - for (var _i = 0, reconciliationFiles_1 = reconciliationFiles; _i < reconciliationFiles_1.length; _i++) { - var file = reconciliationFiles_1[_i]; - var src = path.join(x64Path, file); - var dest = path.join(arm64Path, file); + for (const file of reconciliationFiles) { + const src = path.join(x64Path, file); + const dest = path.join(arm64Path, file); fs.copyFileSync(src, dest); } } function restoreFromStash(stash, destRoot) { - for (var _i = 0, _a = readFiles(stash); _i < _a.length; _i++) { - var src = _a[_i]; - var rel = path.relative(stash, src); - var dest = path.join(destRoot, rel); + for (const src of readFiles(stash)) { + const rel = path.relative(stash, src); + const dest = path.join(destRoot, rel); ensureDir(dest); fs.renameSync(src, dest); } } // --- End Positron --- -function main(buildDir) { - return __awaiter(this, void 0, void 0, function () { - var arch, product, appName, x64AppPath, arm64AppPath, asarRelativePath, outAppPath, productJsonPath, filesToSkip, stash; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - arch = process.env['VSCODE_ARCH']; - if (!buildDir) { - throw new Error('Build dir not provided'); - } - product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); - appName = product.nameLong + '.app'; - x64AppPath = path.join(buildDir, 'VSCode-darwin-x64', appName); - arm64AppPath = path.join(buildDir, 'VSCode-darwin-arm64', appName); - asarRelativePath = path.join('Contents', 'Resources', 'app', 'node_modules.asar'); - outAppPath = path.join(buildDir, "VSCode-darwin-".concat(arch), appName); - productJsonPath = path.resolve(outAppPath, 'Contents', 'Resources', 'app', 'product.json'); - filesToSkip = [ - '**/CodeResources', - '**/Credits.rtf', - ]; - stash = fs.mkdtempSync(path.join(os.tmpdir(), 'positron-create-universal')); - _a.label = 1; - case 1: - _a.trys.push([1, , 3, 4]); - reconcileFiles(x64AppPath, arm64AppPath); - stashFiles(stash, x64AppPath, arm64AppPath); - return [4 /*yield*/, origMain(x64AppPath, arm64AppPath, asarRelativePath, outAppPath, filesToSkip, productJsonPath)]; - case 2: - _a.sent(); - restoreFromStash(path.join(stash, 'x64'), outAppPath); - return [3 /*break*/, 4]; - case 3: - fs.rmSync(stash, { recursive: true, force: true }); - return [7 /*endfinally*/]; - case 4: return [2 /*return*/]; - } - }); - }); +async function main(buildDir) { + const arch = process.env['VSCODE_ARCH']; + if (!buildDir) { + throw new Error('Build dir not provided'); + } + const product = JSON.parse(fs.readFileSync(path.join(root, 'product.json'), 'utf8')); + const appName = product.nameLong + '.app'; + const x64AppPath = path.join(buildDir, 'VSCode-darwin-x64', appName); + const arm64AppPath = path.join(buildDir, 'VSCode-darwin-arm64', appName); + const asarRelativePath = path.join('Contents', 'Resources', 'app', 'node_modules.asar'); + const outAppPath = path.join(buildDir, `VSCode-darwin-${arch}`, appName); + const productJsonPath = path.resolve(outAppPath, 'Contents', 'Resources', 'app', 'product.json'); + const filesToSkip = [ + '**/CodeResources', + '**/Credits.rtf', + ]; + // --- Start Positron --- + // We split the original main function in two parts so that we can call the + // second part in a try block without causing the formatter to increase the + // indentation, which would increase the chance of merge conflicts + const stash = fs.mkdtempSync(path.join(os.tmpdir(), 'positron-create-universal')); + try { + reconcileFiles(x64AppPath, arm64AppPath); + stashFiles(stash, x64AppPath, arm64AppPath); + await origMain(x64AppPath, arm64AppPath, asarRelativePath, outAppPath, filesToSkip, productJsonPath); + restoreFromStash(path.join(stash, 'x64'), outAppPath); + } + finally { + fs.rmSync(stash, { recursive: true, force: true }); + } } -function origMain(x64AppPath, arm64AppPath, asarRelativePath, outAppPath, filesToSkip, productJsonPath) { - return __awaiter(this, void 0, void 0, function () { - var productJson, findOutput, lipoOutput; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - // --- End Positron --- - return [4 /*yield*/, (0, vscode_universal_bundler_1.makeUniversalApp)({ - x64AppPath: x64AppPath, - arm64AppPath: arm64AppPath, - asarPath: asarRelativePath, - outAppPath: outAppPath, - force: true, - mergeASARs: true, - x64ArchFiles: '*/kerberos.node', - filesToSkipComparison: function (file) { - for (var _i = 0, filesToSkip_1 = filesToSkip; _i < filesToSkip_1.length; _i++) { - var expected = filesToSkip_1[_i]; - if (minimatch(file, expected)) { - return true; - } - } - return false; - } - })]; - case 1: - // --- End Positron --- - _a.sent(); - productJson = JSON.parse(fs.readFileSync(productJsonPath, 'utf8')); - Object.assign(productJson, { - darwinUniversalAssetId: 'darwin-universal' - }); - fs.writeFileSync(productJsonPath, JSON.stringify(productJson, null, '\t')); - return [4 /*yield*/, (0, cross_spawn_promise_1.spawn)('find', [outAppPath, '-name', 'kerberos.node'])]; - case 2: - findOutput = _a.sent(); - return [4 /*yield*/, (0, cross_spawn_promise_1.spawn)('lipo', ['-archs', findOutput.replace(/\n$/, '')])]; - case 3: - lipoOutput = _a.sent(); - if (lipoOutput.replace(/\n$/, '') !== 'x86_64 arm64') { - throw new Error("Invalid arch, got : ".concat(lipoOutput)); - } - return [2 /*return*/]; +async function origMain(x64AppPath, arm64AppPath, asarRelativePath, outAppPath, filesToSkip, productJsonPath) { + // --- End Positron --- + const canAsar = !(0, esm_1.isESM)('ASAR disabled in universal build'); // TODO@esm ASAR disabled in ESM + await (0, vscode_universal_bundler_1.makeUniversalApp)({ + x64AppPath, + arm64AppPath, + asarPath: canAsar ? asarRelativePath : undefined, + outAppPath, + force: true, + mergeASARs: canAsar, + x64ArchFiles: '*/kerberos.node', + filesToSkipComparison: (file) => { + for (const expected of filesToSkip) { + if (minimatch(file, expected)) { + return true; + } } - }); + return false; + } }); + const productJson = JSON.parse(fs.readFileSync(productJsonPath, 'utf8')); + Object.assign(productJson, { + darwinUniversalAssetId: 'darwin-universal' + }); + fs.writeFileSync(productJsonPath, JSON.stringify(productJson, null, '\t')); + // Verify if native module architecture is correct + const findOutput = await (0, cross_spawn_promise_1.spawn)('find', [outAppPath, '-name', 'kerberos.node']); + const lipoOutput = await (0, cross_spawn_promise_1.spawn)('lipo', ['-archs', findOutput.replace(/\n$/, '')]); + if (lipoOutput.replace(/\n$/, '') !== 'x86_64 arm64') { + throw new Error(`Invalid arch, got : ${lipoOutput}`); + } } if (require.main === module) { - main(process.argv[2]).catch(function (err) { + main(process.argv[2]).catch(err => { console.error(err); process.exit(1); }); } +//# sourceMappingURL=create-universal-app.js.map \ No newline at end of file diff --git a/build/darwin/create-universal-app.ts b/build/darwin/create-universal-app.ts index 243e2f57e9f..f4ee4d6bb5a 100644 --- a/build/darwin/create-universal-app.ts +++ b/build/darwin/create-universal-app.ts @@ -8,6 +8,7 @@ import * as fs from 'fs'; import * as minimatch from 'minimatch'; import { makeUniversalApp } from 'vscode-universal-bundler'; import { spawn } from '@malept/cross-spawn-promise'; +import { isESM } from '../lib/esm'; const root = path.dirname(path.dirname(__dirname)); @@ -210,13 +211,15 @@ async function origMain( ) { // --- End Positron --- + const canAsar = !isESM('ASAR disabled in universal build'); // TODO@esm ASAR disabled in ESM + await makeUniversalApp({ x64AppPath, arm64AppPath, - asarPath: asarRelativePath, + asarPath: canAsar ? asarRelativePath : undefined, outAppPath, force: true, - mergeASARs: true, + mergeASARs: canAsar, x64ArchFiles: '*/kerberos.node', filesToSkipComparison: (file: string) => { for (const expected of filesToSkip) { diff --git a/build/filters.js b/build/filters.js index 67875742c6c..451143a0e71 100644 --- a/build/filters.js +++ b/build/filters.js @@ -87,7 +87,9 @@ module.exports.indentationFilter = [ '!src/vs/base/common/semver/semver.js', '!src/vs/base/node/terminateProcess.sh', '!src/vs/base/node/cpuUsage.sh', + '!src/vs/editor/common/languages/highlights/*.scm', '!test/unit/assert.js', + '!test/unit/assert-esm.js', '!resources/linux/snap/electron-launch', '!build/ext.js', '!build/npm/gyp/patches/gyp_spectre_mitigation_support.patch', diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js index de8f3c4fb57..c6d7bbded93 100644 --- a/build/gulpfile.compile.js +++ b/build/gulpfile.compile.js @@ -9,10 +9,13 @@ const gulp = require('gulp'); const util = require('./lib/util'); const date = require('./lib/date'); +const esm = require('./lib/esm'); const task = require('./lib/task'); const compilation = require('./lib/compilation'); const optimize = require('./lib/optimize'); +const isESMBuild = typeof process.env.VSCODE_BUILD_ESM === 'string' && process.env.VSCODE_BUILD_ESM.toLowerCase() === 'true'; + /** * @param {boolean} disableMangle */ @@ -21,8 +24,9 @@ function makeCompileBuildTask(disableMangle) { util.rimraf('out-build'), util.buildWebNodePaths('out-build'), date.writeISODate('out-build'), + esm.setESM(isESMBuild), compilation.compileApiProposalNamesTask, - compilation.compileTask('src', 'out-build', true, { disableMangle }), + compilation.compileTask(isESMBuild ? 'src2' : 'src', 'out-build', true, { disableMangle }), optimize.optimizeLoaderTask('out-build', 'out-build', true) ); } diff --git a/build/gulpfile.editor.js b/build/gulpfile.editor.js index fe29d4fe183..088748b8356 100644 --- a/build/gulpfile.editor.js +++ b/build/gulpfile.editor.js @@ -79,7 +79,9 @@ const extractEditorSrcTask = task.define('extract-editor-src', () => { shakeLevel: 2, // 0-Files, 1-InnerFile, 2-ClassMembers importIgnorePattern: /(^vs\/css!)/, destRoot: path.join(root, 'out-editor-src'), - redirects: [] + redirects: { + '@vscode/tree-sitter-wasm': '../node_modules/@vscode/tree-sitter-wasm/wasm/tree-sitter-web', + } }); }); @@ -133,7 +135,8 @@ const compileEditorESMTask = task.define('compile-editor-esm', () => { let result; if (process.platform === 'win32') { result = cp.spawnSync(`..\\node_modules\\.bin\\tsc.cmd`, { - cwd: path.join(__dirname, '../out-editor-esm') + cwd: path.join(__dirname, '../out-editor-esm'), + shell: true }); } else { result = cp.spawnSync(`node`, [`../node_modules/.bin/tsc`], { diff --git a/build/gulpfile.js b/build/gulpfile.js index e945c06eed4..785719d3e14 100644 --- a/build/gulpfile.js +++ b/build/gulpfile.js @@ -34,11 +34,15 @@ gulp.task(compileClientTask); const watchClientTask = task.define('watch-client', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(watchTask('out', false), watchApiProposalNamesTask))); gulp.task(watchClientTask); +const watchClientESMTask = task.define('watch-client-esm', task.series(util.rimraf('out'), util.buildWebNodePaths('out'), task.parallel(watchTask('out', false, 'src2'), watchApiProposalNamesTask))); +gulp.task(watchClientESMTask); + // All const _compileTask = task.define('compile', task.parallel(monacoTypecheckTask, compileClientTask, compileExtensionsTask, compileExtensionMediaTask)); gulp.task(_compileTask); gulp.task(task.define('watch', task.parallel(/* monacoTypecheckWatchTask, */ watchClientTask, watchExtensionsTask))); +gulp.task(task.define('watch-esm', task.parallel(/* monacoTypecheckWatchTask, */ watchClientESMTask, watchExtensionsTask))); // Default gulp.task('default', _compileTask); diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index e31e1d78b5f..f3e0a5e1c43 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -33,6 +33,8 @@ const { vscodeWebEntryPoints, vscodeWebResourceIncludes, createVSCodeWebFileCont // --- End Positron --- const cp = require('child_process'); const log = require('fancy-log'); +const { isESM } = require('./lib/esm'); +const buildfile = require('./buildfile'); const REPO_ROOT = path.dirname(__dirname); const commit = getVersion(REPO_ROOT); @@ -46,6 +48,7 @@ const REMOTE_REH_WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'reh-web'); const BUILD_TARGETS = [ { platform: 'win32', arch: 'x64' }, + { platform: 'win32', arch: 'arm64' }, { platform: 'darwin', arch: 'x64' }, { platform: 'darwin', arch: 'arm64' }, { platform: 'linux', arch: 'x64' }, @@ -57,7 +60,7 @@ const BUILD_TARGETS = [ { platform: 'linux', arch: 'alpine' }, ]; -const serverResources = [ +const serverResourceIncludes = [ // --- Start Positron --- 'out-build/react-dom/client.js', // --- End Positron --- @@ -79,19 +82,40 @@ const serverResources = [ 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-rc.zsh', 'out-build/vs/workbench/contrib/terminal/browser/media/shellIntegration-login.zsh', 'out-build/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/shellIntegration.fish', +]; +const serverResourceExcludes = [ + '!out-build/vs/**/{electron-sandbox,electron-main}/**', + '!out-build/vs/editor/standalone/**', + '!out-build/vs/workbench/**/*-tb.png', '!**/test/**' ]; -const serverWithWebResources = [ - - // Include all of server... - ...serverResources, +const serverResources = [ + ...serverResourceIncludes, + ...serverResourceExcludes +]; - // ...and all of web +const serverWithWebResourceIncludes = isESM() ? [ + ...serverResourceIncludes, + 'out-build/vs/code/browser/workbench/*.html', + ...vscodeWebResourceIncludes +] : [ + ...serverResourceIncludes, ...vscodeWebResourceIncludes ]; +const serverWithWebResourceExcludes = [ + ...serverResourceExcludes, + '!out-build/vs/code/**/*-dev.html', + '!out-build/vs/code/**/*-dev.esm.html', +]; + +const serverWithWebResources = [ + ...serverWithWebResourceIncludes, + ...serverWithWebResourceExcludes +]; + const serverEntryPoints = [ { name: 'vs/server/node/server.main', @@ -115,14 +139,35 @@ const serverEntryPoints = [ } ]; +const webEntryPoints = isESM() ? [ + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.keyboardMaps, + buildfile.codeWeb +].flat() : [ + buildfile.entrypoint('vs/workbench/workbench.web.main'), + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.keyboardMaps, + buildfile.workbenchWeb() +].flat(); + const serverWithWebEntryPoints = [ // Include all of server ...serverEntryPoints, - // Include workbench web - ...vscodeWebEntryPoints -]; + // Include all of web + ...webEntryPoints, +].flat(); const commonJSEntryPoints = [ 'out-build/server-main.js', @@ -298,6 +343,12 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa const marketplaceExtensions = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'product.json'), 'utf8')).builtInExtensions .filter(entry => !entry.platforms || new Set(entry.platforms).has(platform)) .filter(entry => !entry.clientOnly) + // --- Start PWB --- + // If an entry specifies a type, ensure that the type specified + // matches the type we're building. We use this to prevent the + // Workbench extension from being bundled in non-web releases. + .filter(entry => !entry.type || entry.type === type) + // --- End PWB --- .map(entry => entry.name); const extensionPaths = [...localWorkspaceExtensions, ...marketplaceExtensions] .map(name => `.build/extensions/${name}/**`); @@ -326,7 +377,7 @@ function packageTask(type, platform, arch, sourceFolderName, destinationFolderNa // Note: The remote/reh-web/package.json is generated/updated in build/npm/postinstall.js const packageJsonBase = type === 'reh-web' ? 'remote/reh-web' : 'remote'; const packageJsonStream = gulp.src([`${packageJsonBase}/package.json`], { base: packageJsonBase }) - .pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined })) + .pipe(json({ name, version, dependencies: undefined, optionalDependencies: undefined, ...(isESM(`Setting 'type: module' in top level package.json`) ? { type: 'module' } : {}) })) // TODO@esm this should be configured in the top level package.json // --- End Positron --- .pipe(es.through(function (file) { packageJsonContents = file.contents.toString(); diff --git a/build/gulpfile.scan.js b/build/gulpfile.scan.js index 6f8144b0954..127720a0245 100644 --- a/build/gulpfile.scan.js +++ b/build/gulpfile.scan.js @@ -26,6 +26,9 @@ const BUILD_TARGETS = [ { platform: 'linux', arch: 'arm64' }, ]; +// The following files do not have PDBs downloaded for them during the download symbols process. +const excludedCheckList = ['d3dcompiler_47.dll']; + BUILD_TARGETS.forEach(buildTarget => { const dashed = (/** @type {string | null} */ str) => (str ? `-${str}` : ``); const platform = buildTarget.platform; @@ -46,7 +49,6 @@ BUILD_TARGETS.forEach(buildTarget => { if (platform === 'win32') { tasks.push( () => electron.dest(destinationPdb, { ...config, platform, arch: arch === 'armhf' ? 'arm' : arch, pdbs: true }), - util.rimraf(path.join(destinationExe, 'd3dcompiler_47.dll')), () => confirmPdbsExist(destinationExe, destinationPdb) ); } @@ -110,6 +112,10 @@ function nodeModules(destinationExe, destinationPdb, platform) { function confirmPdbsExist(destinationExe, destinationPdb) { readdirSync(destinationExe).forEach(file => { + if (excludedCheckList.includes(file)) { + return; + } + if (file.endsWith('.dll') || file.endsWith('.exe')) { const pdb = `${file}.pdb`; if (!existsSync(path.join(destinationPdb, pdb))) { diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 47c4247aa3c..7ec7150b26b 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -17,7 +17,7 @@ const util = require('./lib/util'); const { getVersion } = require('./lib/getVersion'); const { readISODate } = require('./lib/date'); const task = require('./lib/task'); -const buildfile = require('../src/buildfile'); +const buildfile = require('./buildfile'); const optimize = require('./lib/optimize'); const { inlineMeta } = require('./lib/inlineMeta'); const root = path.dirname(__dirname); @@ -33,6 +33,7 @@ const minimist = require('minimist'); const { compileBuildTask } = require('./gulpfile.compile'); const { compileExtensionsBuildTask, compileExtensionMediaBuildTask } = require('./gulpfile.extensions'); const { promisify } = require('util'); +const { isESM } = require('./lib/esm'); const glob = promisify(require('glob')); const rcedit = promisify(require('rcedit')); @@ -43,7 +44,18 @@ const { getQuartoStream } = require('./lib/quarto'); // --- End Positron --- // Build -const vscodeEntryPoints = [ +const vscodeEntryPoints = isESM() ? [ + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.workbenchDesktop(), + buildfile.code +].flat() : [ buildfile.entrypoint('vs/workbench/workbench.desktop.main'), buildfile.base, buildfile.workerExtensionHost, @@ -51,19 +63,78 @@ const vscodeEntryPoints = [ buildfile.workerLanguageDetection, buildfile.workerLocalFileSearch, buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop, + buildfile.workbenchDesktop(), buildfile.code ].flat(); -const vscodeResources = [ +const vscodeResourceIncludes = isESM() ? [ + // --- Start Positron --- + 'out-build/react-dom/client.js', + // --- End Positron --- + + // NLS + 'out-build/nls.messages.json', + 'out-build/nls.keys.json', + + // Workbench + 'out-build/vs/code/electron-sandbox/workbench/workbench.esm.html', + + // Electron Preload + 'out-build/vs/base/parts/sandbox/electron-sandbox/preload.js', + 'out-build/vs/base/parts/sandbox/electron-sandbox/preload-aux.js', + + // Node Scripts + 'out-build/vs/base/node/{terminateProcess.sh,cpuUsage.sh,ps.sh}', + + // Touchbar + 'out-build/vs/workbench/browser/parts/editor/media/*.png', + 'out-build/vs/workbench/contrib/debug/browser/media/*.png', + + // External Terminal + 'out-build/vs/workbench/contrib/externalTerminal/**/*.scpt', + + // Terminal shell integration + 'out-build/vs/workbench/contrib/terminal/browser/media/fish_xdg_data/fish/vendor_conf.d/*.fish', + 'out-build/vs/workbench/contrib/terminal/browser/media/*.ps1', + 'out-build/vs/workbench/contrib/terminal/browser/media/*.psm1', + 'out-build/vs/workbench/contrib/terminal/browser/media/*.sh', + 'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh', + + // Accessibility Signals + 'out-build/vs/platform/accessibilitySignal/browser/media/*.mp3', + + // Welcome + 'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}', + + // Extensions + 'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}', + 'out-build/vs/workbench/services/extensionManagement/common/media/*.{svg,png}', + + // Webview + 'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}', + + // Extension Host Worker + 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html', + + // Process Explorer + 'out-build/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html', + + // Tree Sitter highlights + 'out-build/vs/editor/common/languages/highlights/*.scm', + + // Issue Reporter + 'out-build/vs/workbench/contrib/issue/electron-sandbox/issueReporter.esm.html' +] : [ // --- Start Positron --- 'out-build/react-dom/client.js', // --- End Positron --- + 'out-build/nls.messages.json', 'out-build/nls.keys.json', 'out-build/vs/**/*.{svg,png,html,jpg,mp3}', '!out-build/vs/code/browser/**/*.html', '!out-build/vs/code/**/*-dev.html', + '!out-build/vs/code/**/*-dev.esm.html', '!out-build/vs/editor/standalone/**/*.svg', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}', 'out-build/vs/base/browser/ui/codicons/codicon/**', @@ -78,21 +149,37 @@ const vscodeResources = [ 'out-build/vs/workbench/contrib/terminal/browser/media/*.sh', 'out-build/vs/workbench/contrib/terminal/browser/media/*.zsh', 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', - '!out-build/vs/workbench/contrib/issue/browser/*.html', '!out-build/vs/workbench/contrib/issue/**/*-dev.html', + '!out-build/vs/workbench/contrib/issue/**/*-dev.esm.html', + 'out-build/vs/editor/common/languages/highlights/*.scm', 'out-build/vs/**/markdown.css', 'out-build/vs/workbench/contrib/tasks/**/*.json', '!**/test/**' ]; +const vscodeResources = [ + + // Includes + ...vscodeResourceIncludes, + + // Excludes + '!out-build/vs/code/browser/**', + '!out-build/vs/editor/standalone/**', + '!out-build/vs/code/**/*-dev.html', + '!out-build/vs/code/**/*-dev.esm.html', + '!out-build/vs/workbench/contrib/issue/**/*-dev.html', + '!out-build/vs/workbench/contrib/issue/**/*-dev.esm.html', + '!**/test/**' +]; + // Do not change the order of these files! They will // be inlined into the target window file in this order // and they depend on each other in this way. -const windowBootstrapFiles = [ - 'out-build/bootstrap.js', - 'out-build/vs/loader.js', - 'out-build/bootstrap-window.js' -]; +const windowBootstrapFiles = []; +if (!isESM('Skipping loader.js in window bootstrap files')) { + windowBootstrapFiles.push('out-build/vs/loader.js'); +} +windowBootstrapFiles.push('out-build/bootstrap-window.js'); const commonJSEntryPoints = [ 'out-build/main.js', @@ -222,7 +309,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op 'vs/workbench/workbench.desktop.main.js', 'vs/workbench/workbench.desktop.main.css', 'vs/workbench/api/node/extensionHostProcess.js', - 'vs/code/electron-sandbox/workbench/workbench.html', + isESM() ? 'vs/code/electron-sandbox/workbench/workbench.esm.html' : 'vs/code/electron-sandbox/workbench/workbench.html', 'vs/code/electron-sandbox/workbench/workbench.js' ]); @@ -231,6 +318,13 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(util.setExecutableBit(['**/*.sh'])); const platformSpecificBuiltInExtensionsExclusions = product.builtInExtensions.filter(ext => { + // --- Start PWB --- + // Don't bundle reh-web extensions here. We bundle them for the + // remote web gulp build targets (see gulpfile.reh.js) + if (ext.type === 'reh-web') { + return true; + } + // --- End PWB --- if (!ext.platforms) { return false; } @@ -264,8 +358,13 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op version += '-' + quality; } + if (isESM() && typeof quality === 'string' && quality !== 'exploration') { + // TODO@esm remove this safeguard + throw new Error('Refuse to build ESM on quality other than exploration'); + } + const name = product.nameShort; - const packageJsonUpdates = { name, version }; + const packageJsonUpdates = { name, version, ...(isESM(`Setting 'type: module' and 'main: out/main.js' in top level package.json`) ? { type: 'module', main: 'out/main.js' } : {}) }; // TODO@esm this should be configured in the top level package.json // for linux url handling if (platform === 'linux') { @@ -333,19 +432,22 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const jsFilter = util.filter(data => !data.isDirectory() && /\.js$/.test(data.path)); const root = path.resolve(path.join(__dirname, '..')); const productionDependencies = getProductionDependencies(root); - const dependenciesSrc = productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]).flat(); + const dependenciesSrc = productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!**/*.mk`]).flat(); - const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) + let deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) .pipe(filter(['**', `!**/${config.version}/**`, '!**/bin/darwin-arm64-87/**', '!**/package-lock.json', '!**/yarn.lock', '!**/*.js.map'])) .pipe(util.cleanNodeModules(path.join(__dirname, '.moduleignore'))) .pipe(util.cleanNodeModules(path.join(__dirname, `.moduleignore.${process.platform}`))) .pipe(jsFilter) .pipe(util.rewriteSourceMappingURL(sourceMappingURLBase)) - .pipe(jsFilter.restore) - .pipe(createAsar(path.join(process.cwd(), 'node_modules'), [ + .pipe(jsFilter.restore); + + if (!isESM('ASAR disabled in VS Code builds')) { // TODO@esm: ASAR disabled in ESM + deps = deps.pipe(createAsar(path.join(process.cwd(), 'node_modules'), [ '**/*.node', '**/@vscode/ripgrep/bin/*', '**/node-pty/build/Release/*', + '**/node-pty/build/Release/conpty/*', '**/node-pty/lib/worker/conoutSocketWorker.js', '**/node-pty/lib/shared/conout.js', '**/*.wasm', @@ -353,6 +455,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op ], [ '**/*.mk', ], 'node_modules.asar')); + } let all = es.merge( packageJsonStream, diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 9c643fa7e58..2c91446487e 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -121,7 +121,11 @@ function prepareDebPackage(arch) { .pipe(replace('@@NAME@@', product.applicationName)) .pipe(rename('DEBIAN/postinst')); - const all = es.merge(control, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code); + const templates = gulp.src('resources/linux/debian/templates.template', { base: '.' }) + .pipe(replace('@@NAME@@', product.applicationName)) + .pipe(rename('DEBIAN/templates')); + + const all = es.merge(control, templates, postinst, postrm, prerm, desktops, appdata, workspaceMime, icon, bash_completion, zsh_completion, code); return all.pipe(vfs.dest(destination)); }; diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js index c705d74d5e2..0296738bd1d 100644 --- a/build/gulpfile.vscode.web.js +++ b/build/gulpfile.vscode.web.js @@ -21,6 +21,7 @@ const vfs = require('vinyl-fs'); const packageJson = require('../package.json'); const { compileBuildTask } = require('./gulpfile.compile'); const extensions = require('./lib/extensions'); +const { isESM } = require('./lib/esm'); // --- Start Positron --- const child_process = require('child_process'); @@ -38,7 +39,30 @@ const version = (quality && quality !== 'stable') ? `${packageJson.version}-${qu const positronVersion = (quality && quality !== 'stable') ? `${product.positronVersion}-${quality}` : product.positronVersion; // --- End Positron --- -const vscodeWebResourceIncludes = [ +const vscodeWebResourceIncludes = isESM() ? [ + + // NLS + 'out-build/nls.messages.js', + + // Accessibility Signals + 'out-build/vs/platform/accessibilitySignal/browser/media/*.mp3', + + // Welcome + 'out-build/vs/workbench/contrib/welcomeGettingStarted/common/media/**/*.{svg,png}', + + // Extensions + 'out-build/vs/workbench/contrib/extensions/browser/media/{theme-icon.png,language-icon.svg}', + 'out-build/vs/workbench/services/extensionManagement/common/media/*.{svg,png}', + + // Webview + 'out-build/vs/workbench/contrib/webview/browser/pre/*.{js,html}', + + // Tree Sitter highlights + 'out-build/vs/editor/common/languages/highlights/*.scm', + + // Extension Host Worker + 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html', +] : [ // Workbench 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,jpg,mp3}', @@ -56,6 +80,9 @@ const vscodeWebResourceIncludes = [ // Extension Worker 'out-build/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html', + // Tree Sitter highlights + 'out-build/vs/editor/common/languages/highlights/*.scm', + // Web node paths (needed for integration tests) 'out-build/vs/webPackagePaths.js', ]; @@ -70,12 +97,24 @@ const vscodeWebResources = [ '!out-build/vs/**/{node,electron-sandbox,electron-main}/**', '!out-build/vs/editor/standalone/**', '!out-build/vs/workbench/**/*-tb.png', + '!out-build/vs/code/**/*-dev.html', + '!out-build/vs/code/**/*-dev.esm.html', '!**/test/**' ]; -const buildfile = require('../src/buildfile'); +const buildfile = require('./buildfile'); -const vscodeWebEntryPoints = [ +const vscodeWebEntryPoints = isESM() ? [ + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.keyboardMaps, + buildfile.workbenchWeb() +].flat() : [ buildfile.entrypoint('vs/workbench/workbench.web.main'), buildfile.base, buildfile.workerExtensionHost, @@ -83,9 +122,8 @@ const vscodeWebEntryPoints = [ buildfile.workerLanguageDetection, buildfile.workerLocalFileSearch, buildfile.keyboardMaps, - buildfile.workbenchWeb + buildfile.workbenchWeb() ].flat(); -exports.vscodeWebEntryPoints = vscodeWebEntryPoints; // --- Begin Positron --- // Use the POSITRON_BUILD_NUMBER var if it's set; otherwise, call show-version to compute it. diff --git a/build/lib/builtInExtensions.js b/build/lib/builtInExtensions.js index 284f1d96e41..bf3a3482ae5 100644 --- a/build/lib/builtInExtensions.js +++ b/build/lib/builtInExtensions.js @@ -46,6 +46,13 @@ function isUpToDate(extension) { } } function getExtensionDownloadStream(extension) { + // --- Start PWB: Bundle PWB extension --- + // the PWB extension is a special case because it's not availble from the marketplace or github + if (extension.name === 'rstudio.rstudio-workbench') { + return ext.fromS3Bucket(extension) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); + } + // --- End PWB: Bundle PWB extension --- // --- Start Positron --- const url = extension.metadata.multiPlatformServiceUrl || productjson.extensionsGallery?.serviceUrl; return (url ? ext.fromMarketplace(url, extension) : ext.fromGithub(extension)) @@ -120,6 +127,15 @@ function getBuiltInExtensions() { for (const extension of [...builtInExtensions, ...webBuiltInExtensions]) { const controlState = control[extension.name] || 'marketplace'; control[extension.name] = controlState; + // --- Start Positron --- + // Discard extensions intended for the web. The 'type' field isn't a + // formal part of the extension definition but a custom field we use to + // filter out web-only extensions (i.e. Posit Workbench) + // @ts-ignore + if (extension.type === 'reh-web') { + continue; + } + // --- End Positron --- streams.push(syncExtension(extension, controlState)); } writeControlFile(control); diff --git a/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts index 11de5d676ca..04d6fb6d65c 100644 --- a/build/lib/builtInExtensions.ts +++ b/build/lib/builtInExtensions.ts @@ -23,6 +23,9 @@ export interface IExtensionDefinition { sha256: string; repo: string; platforms?: string[]; + // --- Start PWB: Bundle PWB extension --- + s3Bucket?: string; + // --- End PWB: Bundle PWB extension --- metadata: { id: string; publisherId: { @@ -73,6 +76,13 @@ function isUpToDate(extension: IExtensionDefinition): boolean { } function getExtensionDownloadStream(extension: IExtensionDefinition) { + // --- Start PWB: Bundle PWB extension --- + // the PWB extension is a special case because it's not availble from the marketplace or github + if (extension.name === 'rstudio.rstudio-workbench') { + return ext.fromS3Bucket(extension) + .pipe(rename(p => p.dirname = `${extension.name}/${p.dirname}`)); + } + // --- End PWB: Bundle PWB extension --- // --- Start Positron --- const url = extension.metadata.multiPlatformServiceUrl || productjson.extensionsGallery?.serviceUrl; return (url ? ext.fromMarketplace(url, extension) : ext.fromGithub(extension)) @@ -167,6 +177,16 @@ export function getBuiltInExtensions(): Promise { const controlState = control[extension.name] || 'marketplace'; control[extension.name] = controlState; + // --- Start Positron --- + // Discard extensions intended for the web. The 'type' field isn't a + // formal part of the extension definition but a custom field we use to + // filter out web-only extensions (i.e. Posit Workbench) + // @ts-ignore + if (extension.type === 'reh-web') { + continue; + } + // --- End Positron --- + streams.push(syncExtension(extension, controlState)); } diff --git a/build/lib/bundle.js b/build/lib/bundle.js index df7c10fa37e..627b9966700 100644 --- a/build/lib/bundle.js +++ b/build/lib/bundle.js @@ -5,7 +5,7 @@ *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.bundle = bundle; -exports.removeDuplicateTSBoilerplate = removeDuplicateTSBoilerplate; +exports.removeAllTSBoilerplate = removeAllTSBoilerplate; const fs = require("fs"); const path = require("path"); const vm = require("vm"); @@ -55,9 +55,6 @@ function bundle(entryPoints, config, callback) { }; for (const moduleId in entryPointsMap) { const entryPoint = entryPointsMap[moduleId]; - if (entryPoint.append) { - entryPoint.append = entryPoint.append.map(resolvePath); - } if (entryPoint.prepend) { entryPoint.prepend = entryPoint.prepend.map(resolvePath); } @@ -105,7 +102,7 @@ function emitEntryPoints(modules, entryPoints) { return allDependencies[module]; }); bundleData.bundles[moduleToBundle] = includedModules; - const res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules, info.prepend || [], info.append || [], info.dest); + const res = emitEntryPoint(modulesMap, modulesGraph, moduleToBundle, includedModules, info.prepend || [], info.dest); result = result.concat(res.files); for (const pluginName in res.usedPlugins) { usedPlugins[pluginName] = usedPlugins[pluginName] || res.usedPlugins[pluginName]; @@ -226,20 +223,24 @@ function removeAllDuplicateTSBoilerplate(destFiles) { }); return destFiles; } +function removeAllTSBoilerplate(source) { + const seen = new Array(BOILERPLATE.length).fill(true, 0, 10); + return removeDuplicateTSBoilerplate(source, seen); +} +// Taken from typescript compiler => emitFiles +const BOILERPLATE = [ + { start: /^var __extends/, end: /^}\)\(\);$/ }, + { start: /^var __assign/, end: /^};$/ }, + { start: /^var __decorate/, end: /^};$/ }, + { start: /^var __metadata/, end: /^};$/ }, + { start: /^var __param/, end: /^};$/ }, + { start: /^var __awaiter/, end: /^};$/ }, + { start: /^var __generator/, end: /^};$/ }, + { start: /^var __createBinding/, end: /^}\)\);$/ }, + { start: /^var __setModuleDefault/, end: /^}\);$/ }, + { start: /^var __importStar/, end: /^};$/ }, +]; function removeDuplicateTSBoilerplate(source, SEEN_BOILERPLATE = []) { - // Taken from typescript compiler => emitFiles - const BOILERPLATE = [ - { start: /^var __extends/, end: /^}\)\(\);$/ }, - { start: /^var __assign/, end: /^};$/ }, - { start: /^var __decorate/, end: /^};$/ }, - { start: /^var __metadata/, end: /^};$/ }, - { start: /^var __param/, end: /^};$/ }, - { start: /^var __awaiter/, end: /^};$/ }, - { start: /^var __generator/, end: /^};$/ }, - { start: /^var __createBinding/, end: /^}\)\);$/ }, - { start: /^var __setModuleDefault/, end: /^}\);$/ }, - { start: /^var __importStar/, end: /^};$/ }, - ]; const lines = source.split(/\r\n|\n|\r/); const newLines = []; let IS_REMOVING_BOILERPLATE = false, END_BOILERPLATE; @@ -274,7 +275,7 @@ function removeDuplicateTSBoilerplate(source, SEEN_BOILERPLATE = []) { } return newLines.join('\n'); } -function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, append, dest) { +function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, dest) { if (!dest) { dest = entryPoint + '.js'; } @@ -348,8 +349,7 @@ function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend, }; }; const toPrepend = (prepend || []).map(toIFile); - const toAppend = (append || []).map(toIFile); - mainResult.sources = toPrepend.concat(mainResult.sources).concat(toAppend); + mainResult.sources = toPrepend.concat(mainResult.sources); return { files: results, usedPlugins: usedPlugins diff --git a/build/lib/bundle.ts b/build/lib/bundle.ts index 74d37fcce55..6e3f96a5062 100644 --- a/build/lib/bundle.ts +++ b/build/lib/bundle.ts @@ -52,8 +52,8 @@ export interface IEntryPoint { include?: string[]; exclude?: string[]; prepend?: IExtraFile[]; - append?: IExtraFile[]; dest?: string; + target?: 'amd' | 'esm'; } interface IEntryPointMap { @@ -157,9 +157,6 @@ export function bundle(entryPoints: IEntryPoint[], config: ILoaderConfig, callba }; for (const moduleId in entryPointsMap) { const entryPoint = entryPointsMap[moduleId]; - if (entryPoint.append) { - entryPoint.append = entryPoint.append.map(resolvePath); - } if (entryPoint.prepend) { entryPoint.prepend = entryPoint.prepend.map(resolvePath); } @@ -223,7 +220,6 @@ function emitEntryPoints(modules: IBuildModuleInfo[], entryPoints: IEntryPointMa moduleToBundle, includedModules, info.prepend || [], - info.append || [], info.dest ); @@ -361,22 +357,26 @@ function removeAllDuplicateTSBoilerplate(destFiles: IConcatFile[]): IConcatFile[ return destFiles; } -export function removeDuplicateTSBoilerplate(source: string, SEEN_BOILERPLATE: boolean[] = []): string { +export function removeAllTSBoilerplate(source: string) { + const seen = new Array(BOILERPLATE.length).fill(true, 0, 10); + return removeDuplicateTSBoilerplate(source, seen); +} - // Taken from typescript compiler => emitFiles - const BOILERPLATE = [ - { start: /^var __extends/, end: /^}\)\(\);$/ }, - { start: /^var __assign/, end: /^};$/ }, - { start: /^var __decorate/, end: /^};$/ }, - { start: /^var __metadata/, end: /^};$/ }, - { start: /^var __param/, end: /^};$/ }, - { start: /^var __awaiter/, end: /^};$/ }, - { start: /^var __generator/, end: /^};$/ }, - { start: /^var __createBinding/, end: /^}\)\);$/ }, - { start: /^var __setModuleDefault/, end: /^}\);$/ }, - { start: /^var __importStar/, end: /^};$/ }, - ]; +// Taken from typescript compiler => emitFiles +const BOILERPLATE = [ + { start: /^var __extends/, end: /^}\)\(\);$/ }, + { start: /^var __assign/, end: /^};$/ }, + { start: /^var __decorate/, end: /^};$/ }, + { start: /^var __metadata/, end: /^};$/ }, + { start: /^var __param/, end: /^};$/ }, + { start: /^var __awaiter/, end: /^};$/ }, + { start: /^var __generator/, end: /^};$/ }, + { start: /^var __createBinding/, end: /^}\)\);$/ }, + { start: /^var __setModuleDefault/, end: /^}\);$/ }, + { start: /^var __importStar/, end: /^};$/ }, +]; +function removeDuplicateTSBoilerplate(source: string, SEEN_BOILERPLATE: boolean[] = []): string { const lines = source.split(/\r\n|\n|\r/); const newLines: string[] = []; let IS_REMOVING_BOILERPLATE = false, END_BOILERPLATE: RegExp; @@ -425,7 +425,6 @@ function emitEntryPoint( entryPoint: string, includedModules: string[], prepend: IExtraFile[], - append: IExtraFile[], dest: string | undefined ): IEmitEntryPointResult { if (!dest) { @@ -511,9 +510,8 @@ function emitEntryPoint( }; const toPrepend = (prepend || []).map(toIFile); - const toAppend = (append || []).map(toIFile); - mainResult.sources = toPrepend.concat(mainResult.sources).concat(toAppend); + mainResult.sources = toPrepend.concat(mainResult.sources); return { files: results, diff --git a/build/lib/compilation.js b/build/lib/compilation.js index c49458532bc..aa77a32c04d 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -142,11 +142,11 @@ function compileTask(src, out, build, options = {}) { task.taskName = `compile-${path.basename(src)}`; return task; } -function watchTask(out, build) { +function watchTask(out, build, srcPath = 'src') { const task = () => { - const compile = createCompile('src', { build, emitError: false, transpileOnly: false, preserveEnglish: false }); - const src = gulp.src('src/**', { base: 'src' }); - const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); + const compile = createCompile(srcPath, { build, emitError: false, transpileOnly: false, preserveEnglish: false }); + const src = gulp.src(`${srcPath}/**`, { base: srcPath }); + const watchSrc = watch(`${srcPath}/**`, { base: srcPath, readDelay: 200 }); const generator = new MonacoGenerator(true); generator.execute(); return watchSrc diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index e2ff72894ea..0e015a8ce9d 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -173,13 +173,13 @@ export function compileTask(src: string, out: string, build: boolean, options: { return task; } -export function watchTask(out: string, build: boolean): task.StreamTask { +export function watchTask(out: string, build: boolean, srcPath: string = 'src'): task.StreamTask { const task = () => { - const compile = createCompile('src', { build, emitError: false, transpileOnly: false, preserveEnglish: false }); + const compile = createCompile(srcPath, { build, emitError: false, transpileOnly: false, preserveEnglish: false }); - const src = gulp.src('src/**', { base: 'src' }); - const watchSrc = watch('src/**', { base: 'src', readDelay: 200 }); + const src = gulp.src(`${srcPath}/**`, { base: srcPath }); + const watchSrc = watch(`${srcPath}/**`, { base: srcPath, readDelay: 200 }); const generator = new MonacoGenerator(true); generator.execute(); diff --git a/build/lib/esm.js b/build/lib/esm.js new file mode 100644 index 00000000000..db2683445a2 --- /dev/null +++ b/build/lib/esm.js @@ -0,0 +1,41 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setESM = setESM; +exports.isESM = isESM; +const path = require("path"); +const fs = require("fs"); +// TODO@esm remove this +const outDirectory = path.join(__dirname, '..', '..', 'out-build'); +const esmMarkerFile = path.join(outDirectory, 'esm'); +function setESM(enabled) { + const result = () => new Promise((resolve, _) => { + if (enabled) { + fs.mkdirSync(outDirectory, { recursive: true }); + fs.writeFileSync(esmMarkerFile, 'true', 'utf8'); + console.warn(`Setting build to ESM: true`); + } + else { + console.warn(`Setting build to ESM: false`); + } + resolve(); + }); + result.taskName = 'set-esm'; + return result; +} +function isESM(logWarning) { + try { + const res = (typeof process.env.VSCODE_BUILD_ESM === 'string' && process.env.VSCODE_BUILD_ESM.toLowerCase() === 'true') || (fs.readFileSync(esmMarkerFile, 'utf8') === 'true'); + if (res && logWarning) { + console.warn(`[esm] ${logWarning}`); + } + return res; + } + catch (error) { + return false; + } +} +//# sourceMappingURL=esm.js.map \ No newline at end of file diff --git a/build/lib/esm.ts b/build/lib/esm.ts new file mode 100644 index 00000000000..2fc5215e284 --- /dev/null +++ b/build/lib/esm.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'path'; +import * as fs from 'fs'; + +// TODO@esm remove this + +const outDirectory = path.join(__dirname, '..', '..', 'out-build'); +const esmMarkerFile = path.join(outDirectory, 'esm'); + +export function setESM(enabled: boolean) { + const result = () => new Promise((resolve, _) => { + if (enabled) { + fs.mkdirSync(outDirectory, { recursive: true }); + fs.writeFileSync(esmMarkerFile, 'true', 'utf8'); + console.warn(`Setting build to ESM: true`); + } else { + console.warn(`Setting build to ESM: false`); + } + + resolve(); + }); + result.taskName = 'set-esm'; + return result; +} + +export function isESM(logWarning?: string): boolean { + try { + const res = (typeof process.env.VSCODE_BUILD_ESM === 'string' && process.env.VSCODE_BUILD_ESM.toLowerCase() === 'true') || (fs.readFileSync(esmMarkerFile, 'utf8') === 'true'); + if (res && logWarning) { + console.warn(`[esm] ${logWarning}`); + } + return res; + } catch (error) { + return false; + } +} diff --git a/build/lib/extensions.js b/build/lib/extensions.js index a4c1ebca059..e9e653a2379 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -5,6 +5,7 @@ *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.fromMarketplace = fromMarketplace; +exports.fromS3Bucket = fromS3Bucket; exports.fromGithub = fromGithub; exports.packageLocalExtensionsStream = packageLocalExtensionsStream; exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; @@ -253,6 +254,29 @@ function fromMarketplace(serviceUrl, { name: extensionName, version, sha256, met .pipe(json({ __metadata: metadata })) .pipe(packageJsonFilter.restore); } +// --- Start PWB: Bundle PWB extension --- +function fromS3Bucket({ name: extensionName, version, sha256, s3Bucket, metadata }) { + const json = require('gulp-json-editor'); + const [, name] = extensionName.split('.'); + const url = `https://${s3Bucket}.s3.amazonaws.com/${name}-${version}.vsix`; + fancyLog('Downloading extension from S3:', ansiColors.yellow(`${extensionName}@${version}`), '...'); + const packageJsonFilter = filter('package.json', { restore: true }); + return (0, fetch_1.fetchUrls)('', { + base: url, + nodeFetchOptions: { + headers: baseHeaders + }, + checksumSha256: sha256 + }) + .pipe(vzip.src()) + .pipe(filter('extension/**')) + .pipe(rename(p => p.dirname = p.dirname.replace(/^extension\/?/, ''))) + .pipe(packageJsonFilter) + .pipe(buffer()) + .pipe(json({ __metadata: metadata })) + .pipe(packageJsonFilter.restore); +} +// --- End PWB: Bundle PWB extension --- function fromGithub({ name, version, repo, sha256, metadata }) { const json = require('gulp-json-editor'); fancyLog('Downloading extension from GH:', ansiColors.yellow(`${name}@${version}`), '...'); @@ -522,9 +546,6 @@ async function esbuildExtensions(taskName, isWatch, scripts) { return reject(error); } reporter(stderr, script); - if (stderr) { - return reject(); - } return resolve(); }); proc.stdout.on('data', (data) => { diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index fa0db4f328a..0e675b4f4a1 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -280,6 +280,33 @@ export function fromMarketplace(serviceUrl: string, { name: extensionName, versi .pipe(packageJsonFilter.restore); } +// --- Start PWB: Bundle PWB extension --- +export function fromS3Bucket({ name: extensionName, version, sha256, s3Bucket, metadata }: IExtensionDefinition): Stream { + const json = require('gulp-json-editor') as typeof import('gulp-json-editor'); + + const [, name] = extensionName.split('.'); + const url = `https://${s3Bucket}.s3.amazonaws.com/${name}-${version}.vsix`; + + fancyLog('Downloading extension from S3:', ansiColors.yellow(`${extensionName}@${version}`), '...'); + + const packageJsonFilter = filter('package.json', { restore: true }); + + return fetchUrls('', { + base: url, + nodeFetchOptions: { + headers: baseHeaders + }, + checksumSha256: sha256 + }) + .pipe(vzip.src()) + .pipe(filter('extension/**')) + .pipe(rename(p => p.dirname = p.dirname!.replace(/^extension\/?/, ''))) + .pipe(packageJsonFilter) + .pipe(buffer()) + .pipe(json({ __metadata: metadata })) + .pipe(packageJsonFilter.restore); +} +// --- End PWB: Bundle PWB extension --- export function fromGithub({ name, version, repo, sha256, metadata }: IExtensionDefinition): Stream { const json = require('gulp-json-editor') as typeof import('gulp-json-editor'); @@ -603,9 +630,6 @@ async function esbuildExtensions(taskName: string, isWatch: boolean, scripts: { return reject(error); } reporter(stderr, script); - if (stderr) { - return reject(); - } return resolve(); }); diff --git a/build/lib/i18n.js b/build/lib/i18n.js index a837cbc4ac0..6964616291b 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -316,7 +316,7 @@ globalThis._VSCODE_NLS_LANGUAGE=${JSON.stringify(language.id)};`), function processNlsFiles(opts) { return (0, event_stream_1.through)(function (file) { const fileName = path.basename(file.path); - if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles + if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles (TODO@esm this file is not created anymore, pick another) try { const json = JSON.parse(fs.readFileSync(path.join(REPO_ROOT_PATH, opts.out, 'nls.keys.json')).toString()); if (NLSKeysFormat.is(json)) { diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 588724b131f..4fabe233b0f 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -677,6 +677,14 @@ { "name": "vs/workbench/contrib/authentication", "project": "vscode-workbench" + }, + { + "name": "vs/workbench/contrib/replNotebook", + "project": "vscode-workbench" + }, + { + "name": "vs/workbench/contrib/list", + "project": "vscode-workbench" } ] } diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 28f8cc993e6..cd7e522ad36 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -387,7 +387,7 @@ globalThis._VSCODE_NLS_LANGUAGE=${JSON.stringify(language.id)};`), export function processNlsFiles(opts: { out: string; fileHeader: string; languages: Language[] }): ThroughStream { return through(function (this: ThroughStream, file: File) { const fileName = path.basename(file.path); - if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles + if (fileName === 'bundleInfo.json') { // pick a root level file to put the core bundles (TODO@esm this file is not created anymore, pick another) try { const json = JSON.parse(fs.readFileSync(path.join(REPO_ROOT_PATH, opts.out, 'nls.keys.json')).toString()); if (NLSKeysFormat.is(json)) { diff --git a/build/lib/mangle/index.js b/build/lib/mangle/index.js index 10e1aeb0d5a..f72d299930b 100644 --- a/build/lib/mangle/index.js +++ b/build/lib/mangle/index.js @@ -14,7 +14,8 @@ const ts = require("typescript"); const url_1 = require("url"); const workerpool = require("workerpool"); const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost"); -const buildfile = require('../../../src/buildfile'); +const esm_1 = require("../esm"); +const buildfile = require('../../buildfile'); class ShortIdent { prefix; static _keywords = new Set(['await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', @@ -247,35 +248,51 @@ function isNameTakenInFile(node, name) { } return false; } -const skippedExportMangledFiles = [ - // Build - 'css.build', - // Monaco - 'editorCommon', - 'editorOptions', - 'editorZoom', - 'standaloneEditor', - 'standaloneEnums', - 'standaloneLanguages', - // Generated - 'extensionsApiProposals', - // Module passed around as type - 'pfs', - // entry points - ...[ - buildfile.entrypoint('vs/server/node/server.main', []), - buildfile.entrypoint('vs/workbench/workbench.desktop.main', []), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop, - buildfile.workbenchWeb, - buildfile.code - ].flat().map(x => x.name), -]; +const skippedExportMangledFiles = function () { + return [ + // Build + 'css.build', + // Monaco + 'editorCommon', + 'editorOptions', + 'editorZoom', + 'standaloneEditor', + 'standaloneEnums', + 'standaloneLanguages', + // Generated + 'extensionsApiProposals', + // Module passed around as type + 'pfs', + // entry points + ...(0, esm_1.isESM)() ? [ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.workbenchDesktop(), + buildfile.workbenchWeb(), + buildfile.code, + buildfile.codeWeb + ].flat().map(x => x.name) : [ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.entrypoint('vs/workbench/workbench.desktop.main'), + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workbenchDesktop(), + buildfile.workbenchWeb(), + buildfile.code + ].flat().map(x => x.name), + ]; +}; const skippedExportMangledProjects = [ // Test projects 'vscode-api-tests', @@ -519,7 +536,7 @@ class Mangler { for (const data of this.allExportedSymbols.values()) { if (data.fileName.endsWith('.d.ts') || skippedExportMangledProjects.some(proj => data.fileName.includes(proj)) - || skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))) { + || skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts'))) { continue; } if (!data.shouldMangle(data.replacementName)) { diff --git a/build/lib/mangle/index.ts b/build/lib/mangle/index.ts index a148c4dd637..7b6c6d20843 100644 --- a/build/lib/mangle/index.ts +++ b/build/lib/mangle/index.ts @@ -12,7 +12,8 @@ import * as ts from 'typescript'; import { pathToFileURL } from 'url'; import * as workerpool from 'workerpool'; import { StaticLanguageServiceHost } from './staticLanguageServiceHost'; -const buildfile = require('../../../src/buildfile'); +import { isESM } from '../esm'; +const buildfile = require('../../buildfile'); class ShortIdent { @@ -279,40 +280,55 @@ function isNameTakenInFile(node: ts.Node, name: string): boolean { return false; } - -const skippedExportMangledFiles = [ - // Build - 'css.build', - - // Monaco - 'editorCommon', - 'editorOptions', - 'editorZoom', - 'standaloneEditor', - 'standaloneEnums', - 'standaloneLanguages', - - // Generated - 'extensionsApiProposals', - - // Module passed around as type - 'pfs', - - // entry points - ...[ - buildfile.entrypoint('vs/server/node/server.main', []), - buildfile.entrypoint('vs/workbench/workbench.desktop.main', []), - buildfile.base, - buildfile.workerExtensionHost, - buildfile.workerNotebook, - buildfile.workerLanguageDetection, - buildfile.workerLocalFileSearch, - buildfile.workerProfileAnalysis, - buildfile.workbenchDesktop, - buildfile.workbenchWeb, - buildfile.code - ].flat().map(x => x.name), -]; +const skippedExportMangledFiles = function () { // using a function() to ensure late isESM() check + return [ + // Build + 'css.build', + + // Monaco + 'editorCommon', + 'editorOptions', + 'editorZoom', + 'standaloneEditor', + 'standaloneEnums', + 'standaloneLanguages', + + // Generated + 'extensionsApiProposals', + + // Module passed around as type + 'pfs', + + // entry points + ...isESM() ? [ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workerOutputLinks, + buildfile.workerBackgroundTokenization, + buildfile.workbenchDesktop(), + buildfile.workbenchWeb(), + buildfile.code, + buildfile.codeWeb + ].flat().map(x => x.name) : [ + buildfile.entrypoint('vs/server/node/server.main'), + buildfile.entrypoint('vs/workbench/workbench.desktop.main'), + buildfile.base, + buildfile.workerExtensionHost, + buildfile.workerNotebook, + buildfile.workerLanguageDetection, + buildfile.workerLocalFileSearch, + buildfile.workerProfileAnalysis, + buildfile.workbenchDesktop(), + buildfile.workbenchWeb(), + buildfile.code + ].flat().map(x => x.name), + ]; +}; const skippedExportMangledProjects = [ // Test projects @@ -609,7 +625,7 @@ export class Mangler { for (const data of this.allExportedSymbols.values()) { if (data.fileName.endsWith('.d.ts') || skippedExportMangledProjects.some(proj => data.fileName.includes(proj)) - || skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts')) + || skippedExportMangledFiles().some(file => data.fileName.endsWith(file + '.ts')) ) { continue; } diff --git a/build/lib/nls.js b/build/lib/nls.js index ae235a5a534..3fc4ba3ed61 100644 --- a/build/lib/nls.js +++ b/build/lib/nls.js @@ -10,6 +10,8 @@ const event_stream_1 = require("event-stream"); const File = require("vinyl"); const sm = require("source-map"); const path = require("path"); +const sort = require("gulp-sort"); +const esm_1 = require("./esm"); var CollectStepResult; (function (CollectStepResult) { CollectStepResult[CollectStepResult["Yes"] = 0] = "Yes"; @@ -44,7 +46,9 @@ function clone(object) { function nls(options) { let base; const input = (0, event_stream_1.through)(); - const output = input.pipe((0, event_stream_1.through)(function (f) { + const output = input + .pipe(sort()) // IMPORTANT: to ensure stable NLS metadata generation, we must sort the files because NLS messages are globally extracted and indexed across all files + .pipe((0, event_stream_1.through)(function (f) { if (!f.sourceMap) { return this.emit('error', new Error(`File ${f.relative} does not have sourcemaps.`)); } @@ -166,13 +170,23 @@ var _nls; .filter(n => n.kind === ts.SyntaxKind.ImportEqualsDeclaration) .map(n => n) .filter(d => d.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) - .filter(d => d.moduleReference.expression.getText() === '\'vs/nls\''); + .filter(d => { + if ((0, esm_1.isESM)()) { + return d.moduleReference.expression.getText().endsWith(`/nls.js'`); + } + return d.moduleReference.expression.getText() === '\'vs/nls\''; + }); // import ... from 'vs/nls'; const importDeclarations = imports .filter(n => n.kind === ts.SyntaxKind.ImportDeclaration) .map(n => n) .filter(d => d.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) - .filter(d => d.moduleSpecifier.getText() === '\'vs/nls\'') + .filter(d => { + if ((0, esm_1.isESM)()) { + return d.moduleSpecifier.getText().endsWith(`/nls.js'`); + } + return d.moduleSpecifier.getText() === '\'vs/nls\''; + }) .filter(d => !!d.importClause && !!d.importClause.namedBindings); // `nls.localize(...)` calls const nlsLocalizeCallExpressions = importDeclarations diff --git a/build/lib/nls.ts b/build/lib/nls.ts index 066dc1440c2..0a60f74a770 100644 --- a/build/lib/nls.ts +++ b/build/lib/nls.ts @@ -8,7 +8,9 @@ import * as lazy from 'lazy.js'; import { duplex, through } from 'event-stream'; import * as File from 'vinyl'; import * as sm from 'source-map'; -import * as path from 'path'; +import * as path from 'path'; +import * as sort from 'gulp-sort'; +import { isESM } from './esm'; declare class FileSourceMap extends File { public sourceMap: sm.RawSourceMap; @@ -54,62 +56,64 @@ function clone(object: T): T { export function nls(options: { preserveEnglish: boolean }): NodeJS.ReadWriteStream { let base: string; const input = through(); - const output = input.pipe(through(function (f: FileSourceMap) { - if (!f.sourceMap) { - return this.emit('error', new Error(`File ${f.relative} does not have sourcemaps.`)); - } + const output = input + .pipe(sort()) // IMPORTANT: to ensure stable NLS metadata generation, we must sort the files because NLS messages are globally extracted and indexed across all files + .pipe(through(function (f: FileSourceMap) { + if (!f.sourceMap) { + return this.emit('error', new Error(`File ${f.relative} does not have sourcemaps.`)); + } - let source = f.sourceMap.sources[0]; - if (!source) { - return this.emit('error', new Error(`File ${f.relative} does not have a source in the source map.`)); - } + let source = f.sourceMap.sources[0]; + if (!source) { + return this.emit('error', new Error(`File ${f.relative} does not have a source in the source map.`)); + } - const root = f.sourceMap.sourceRoot; - if (root) { - source = path.join(root, source); - } + const root = f.sourceMap.sourceRoot; + if (root) { + source = path.join(root, source); + } - const typescript = f.sourceMap.sourcesContent![0]; - if (!typescript) { - return this.emit('error', new Error(`File ${f.relative} does not have the original content in the source map.`)); - } + const typescript = f.sourceMap.sourcesContent![0]; + if (!typescript) { + return this.emit('error', new Error(`File ${f.relative} does not have the original content in the source map.`)); + } - base = f.base; - this.emit('data', _nls.patchFile(f, typescript, options)); - }, function () { - for (const file of [ - new File({ - contents: Buffer.from(JSON.stringify({ - keys: _nls.moduleToNLSKeys, - messages: _nls.moduleToNLSMessages, - }, null, '\t')), - base, - path: `${base}/nls.metadata.json` - }), - new File({ - contents: Buffer.from(JSON.stringify(_nls.allNLSMessages)), - base, - path: `${base}/nls.messages.json` - }), - new File({ - contents: Buffer.from(JSON.stringify(_nls.allNLSModulesAndKeys)), - base, - path: `${base}/nls.keys.json` - }), - new File({ - contents: Buffer.from(`/*--------------------------------------------------------- + base = f.base; + this.emit('data', _nls.patchFile(f, typescript, options)); + }, function () { + for (const file of [ + new File({ + contents: Buffer.from(JSON.stringify({ + keys: _nls.moduleToNLSKeys, + messages: _nls.moduleToNLSMessages, + }, null, '\t')), + base, + path: `${base}/nls.metadata.json` + }), + new File({ + contents: Buffer.from(JSON.stringify(_nls.allNLSMessages)), + base, + path: `${base}/nls.messages.json` + }), + new File({ + contents: Buffer.from(JSON.stringify(_nls.allNLSModulesAndKeys)), + base, + path: `${base}/nls.keys.json` + }), + new File({ + contents: Buffer.from(`/*--------------------------------------------------------- * Copyright (C) Microsoft Corporation. All rights reserved. *--------------------------------------------------------*/ globalThis._VSCODE_NLS_MESSAGES=${JSON.stringify(_nls.allNLSMessages)};`), - base, - path: `${base}/nls.messages.js` - }) - ]) { - this.emit('data', file); - } + base, + path: `${base}/nls.messages.js` + }) + ]) { + this.emit('data', file); + } - this.emit('end'); - })); + this.emit('end'); + })); return duplex(input, output); } @@ -228,14 +232,24 @@ module _nls { .filter(n => n.kind === ts.SyntaxKind.ImportEqualsDeclaration) .map(n => n) .filter(d => d.moduleReference.kind === ts.SyntaxKind.ExternalModuleReference) - .filter(d => (d.moduleReference).expression.getText() === '\'vs/nls\''); + .filter(d => { + if (isESM()) { + return (d.moduleReference).expression.getText().endsWith(`/nls.js'`); + } + return (d.moduleReference).expression.getText() === '\'vs/nls\''; + }); // import ... from 'vs/nls'; const importDeclarations = imports .filter(n => n.kind === ts.SyntaxKind.ImportDeclaration) .map(n => n) .filter(d => d.moduleSpecifier.kind === ts.SyntaxKind.StringLiteral) - .filter(d => d.moduleSpecifier.getText() === '\'vs/nls\'') + .filter(d => { + if (isESM()) { + return d.moduleSpecifier.getText().endsWith(`/nls.js'`); + } + return d.moduleSpecifier.getText() === '\'vs/nls\''; + }) .filter(d => !!d.importClause && !!d.importClause.namedBindings); // `nls.localize(...)` calls diff --git a/build/lib/optimize.js b/build/lib/optimize.js index 79509e9a2d5..fdf738576c2 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -15,6 +15,7 @@ const filter = require("gulp-filter"); const fancyLog = require("fancy-log"); const ansiColors = require("ansi-colors"); const path = require("path"); +const fs = require("fs"); const pump = require("pump"); const VinylFile = require("vinyl"); const bundle = require("./bundle"); @@ -22,6 +23,9 @@ const i18n_1 = require("./i18n"); const stats_1 = require("./stats"); const util = require("./util"); const postcss_1 = require("./postcss"); +const esbuild = require("esbuild"); +const sourcemaps = require("gulp-sourcemaps"); +const esm_1 = require("./esm"); const REPO_ROOT_PATH = path.join(__dirname, '../..'); function log(prefix, message) { fancyLog(ansiColors.cyan('[' + prefix + ']'), message); @@ -148,12 +152,11 @@ const DEFAULT_FILE_HEADER = [ ].join('\n'); function optimizeAMDTask(opts) { const src = opts.src; - const entryPoints = opts.entryPoints; + const entryPoints = opts.entryPoints.filter(d => d.target !== 'esm'); const resources = opts.resources; const loaderConfig = opts.loaderConfig; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const fileContentMapper = opts.fileContentMapper || ((contents, _path) => contents); - const sourcemaps = require('gulp-sourcemaps'); const bundlesStream = es.through(); // this stream will contain the bundled files const resourcesStream = es.through(); // this stream will contain the resources const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json @@ -194,8 +197,122 @@ function optimizeAMDTask(opts) { languages: opts.languages }) : es.through()); } +function optimizeESMTask(opts, cjsOpts) { + const resourcesStream = es.through(); // this stream will contain the resources + const bundlesStream = es.through(); // this stream will contain the bundled files + const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd'); + if (cjsOpts) { + cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name })); + } + const allMentionedModules = new Set(); + for (const entryPoint of entryPoints) { + allMentionedModules.add(entryPoint.name); + entryPoint.include?.forEach(allMentionedModules.add, allMentionedModules); + entryPoint.exclude?.forEach(allMentionedModules.add, allMentionedModules); + } + allMentionedModules.delete('vs/css'); // TODO@esm remove this when vs/css is removed + const bundleAsync = async () => { + const files = []; + const tasks = []; + for (const entryPoint of entryPoints) { + console.log(`[bundle] '${entryPoint.name}'`); + // support for 'dest' via esbuild#in/out + const dest = entryPoint.dest?.replace(/\.[^/.]+$/, '') ?? entryPoint.name; + // boilerplate massage + const banner = { js: '' }; + const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js'); + banner.js += await fs.promises.readFile(tslibPath, 'utf-8'); + const boilerplateTrimmer = { + name: 'boilerplate-trimmer', + setup(build) { + build.onLoad({ filter: /\.js$/ }, async (args) => { + const contents = await fs.promises.readFile(args.path, 'utf-8'); + const newContents = bundle.removeAllTSBoilerplate(contents); + return { contents: newContents }; + }); + } + }; + // support for 'preprend' via the esbuild#banner + if (entryPoint.prepend?.length) { + for (const item of entryPoint.prepend) { + const fullpath = path.join(REPO_ROOT_PATH, opts.src, item.path); + const source = await fs.promises.readFile(fullpath, 'utf8'); + banner.js += source + '\n'; + } + } + const task = esbuild.build({ + bundle: true, + external: entryPoint.exclude, + packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages + platform: 'neutral', // makes esm + format: 'esm', + plugins: [boilerplateTrimmer], + target: ['es2022'], + loader: { + '.ttf': 'file', + '.svg': 'file', + '.png': 'file', + '.sh': 'file', + }, + assetNames: 'media/[name]', // moves media assets into a sub-folder "media" + banner, + entryPoints: [ + { + in: path.join(REPO_ROOT_PATH, opts.src, `${entryPoint.name}.js`), + out: dest, + } + ], + outdir: path.join(REPO_ROOT_PATH, opts.src), + write: false, // enables res.outputFiles + metafile: true, // enables res.metafile + }).then(res => { + for (const file of res.outputFiles) { + let contents = file.contents; + if (file.path.endsWith('.js')) { + if (opts.fileContentMapper) { + // UGLY the fileContentMapper is per file but at this point we have all files + // bundled already. So, we call the mapper for the same contents but each file + // that has been included in the bundle... + let newText = file.text; + for (const input of Object.keys(res.metafile.inputs)) { + newText = opts.fileContentMapper(newText, input); + } + contents = Buffer.from(newText); + } + } + files.push(new VinylFile({ + contents: Buffer.from(contents), + path: file.path, + base: path.join(REPO_ROOT_PATH, opts.src) + })); + } + }); + // await task; // FORCE serial bundling (makes debugging easier) + tasks.push(task); + } + await Promise.all(tasks); + return { files }; + }; + bundleAsync().then((output) => { + // bundle output (JS, CSS, SVG...) + es.readArray(output.files).pipe(bundlesStream); + // forward all resources + gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); + }); + const result = es.merge(bundlesStream, resourcesStream); + return result + .pipe(sourcemaps.write('./', { + sourceRoot: undefined, + addComment: true, + includeContent: true + })) + .pipe(opts.languages && opts.languages.length ? (0, i18n_1.processNlsFiles)({ + out: opts.src, + fileHeader: opts.header || DEFAULT_FILE_HEADER, + languages: opts.languages + }) : es.through()); +} function optimizeCommonJSTask(opts) { - const esbuild = require('esbuild'); const src = opts.src; const entryPoints = opts.entryPoints; return gulp.src(entryPoints, { base: `${src}`, allowEmpty: true }) @@ -226,9 +343,15 @@ function optimizeLoaderTask(src, out, bundleLoader, bundledFileHeader = '', exte } function optimizeTask(opts) { return function () { - const optimizers = [optimizeAMDTask(opts.amd)]; - if (opts.commonJS) { - optimizers.push(optimizeCommonJSTask(opts.commonJS)); + const optimizers = []; + if ((0, esm_1.isESM)('Running optimizer in ESM mode')) { + optimizers.push(optimizeESMTask(opts.amd, opts.commonJS)); + } + else { + optimizers.push(optimizeAMDTask(opts.amd)); + if (opts.commonJS) { + optimizers.push(optimizeCommonJSTask(opts.commonJS)); + } } if (opts.manual) { optimizers.push(optimizeManualTask(opts.manual)); @@ -237,11 +360,9 @@ function optimizeTask(opts) { }; } function minifyTask(src, sourceMapBaseUrl) { - const esbuild = require('esbuild'); const sourceMappingURL = sourceMapBaseUrl ? ((f) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined; return cb => { const cssnano = require('cssnano'); - const sourcemaps = require('gulp-sourcemaps'); const svgmin = require('gulp-svgmin'); const jsFilter = filter('**/*.js', { restore: true }); const cssFilter = filter('**/*.css', { restore: true }); @@ -253,7 +374,7 @@ function minifyTask(src, sourceMapBaseUrl) { sourcemap: 'external', outdir: '.', platform: 'node', - target: ['esnext'], + target: ['es2022'], write: false }).then(res => { const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path)); diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index 6f9786b4d1e..c7503213456 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -10,6 +10,7 @@ import * as filter from 'gulp-filter'; import * as fancyLog from 'fancy-log'; import * as ansiColors from 'ansi-colors'; import * as path from 'path'; +import * as fs from 'fs'; import * as pump from 'pump'; import * as VinylFile from 'vinyl'; import * as bundle from './bundle'; @@ -17,6 +18,9 @@ import { Language, processNlsFiles } from './i18n'; import { createStatsStream } from './stats'; import * as util from './util'; import { gulpPostcss } from './postcss'; +import * as esbuild from 'esbuild'; +import * as sourcemaps from 'gulp-sourcemaps'; +import { isESM } from './esm'; const REPO_ROOT_PATH = path.join(__dirname, '../..'); @@ -213,14 +217,12 @@ const DEFAULT_FILE_HEADER = [ function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream { const src = opts.src; - const entryPoints = opts.entryPoints; + const entryPoints = opts.entryPoints.filter(d => d.target !== 'esm'); const resources = opts.resources; const loaderConfig = opts.loaderConfig; const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const fileContentMapper = opts.fileContentMapper || ((contents: string, _path: string) => contents); - const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps'); - const bundlesStream = es.through(); // this stream will contain the bundled files const resourcesStream = es.through(); // this stream will contain the resources const bundleInfoStream = es.through(); // this stream will contain bundleInfo.json @@ -271,6 +273,149 @@ function optimizeAMDTask(opts: IOptimizeAMDTaskOpts): NodeJS.ReadWriteStream { }) : es.through()); } +function optimizeESMTask(opts: IOptimizeAMDTaskOpts, cjsOpts?: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream { + const resourcesStream = es.through(); // this stream will contain the resources + const bundlesStream = es.through(); // this stream will contain the bundled files + + const entryPoints = opts.entryPoints.filter(d => d.target !== 'amd'); + if (cjsOpts) { + cjsOpts.entryPoints.forEach(entryPoint => entryPoints.push({ name: path.parse(entryPoint).name })); + } + + const allMentionedModules = new Set(); + for (const entryPoint of entryPoints) { + allMentionedModules.add(entryPoint.name); + entryPoint.include?.forEach(allMentionedModules.add, allMentionedModules); + entryPoint.exclude?.forEach(allMentionedModules.add, allMentionedModules); + } + + allMentionedModules.delete('vs/css'); // TODO@esm remove this when vs/css is removed + + const bundleAsync = async () => { + + const files: VinylFile[] = []; + const tasks: Promise[] = []; + + for (const entryPoint of entryPoints) { + + console.log(`[bundle] '${entryPoint.name}'`); + + // support for 'dest' via esbuild#in/out + const dest = entryPoint.dest?.replace(/\.[^/.]+$/, '') ?? entryPoint.name; + + // boilerplate massage + const banner = { js: '' }; + const tslibPath = path.join(require.resolve('tslib'), '../tslib.es6.js'); + banner.js += await fs.promises.readFile(tslibPath, 'utf-8'); + + const boilerplateTrimmer: esbuild.Plugin = { + name: 'boilerplate-trimmer', + setup(build) { + build.onLoad({ filter: /\.js$/ }, async args => { + const contents = await fs.promises.readFile(args.path, 'utf-8'); + const newContents = bundle.removeAllTSBoilerplate(contents); + return { contents: newContents }; + }); + } + }; + + // support for 'preprend' via the esbuild#banner + if (entryPoint.prepend?.length) { + for (const item of entryPoint.prepend) { + const fullpath = path.join(REPO_ROOT_PATH, opts.src, item.path); + const source = await fs.promises.readFile(fullpath, 'utf8'); + banner.js += source + '\n'; + } + } + + const task = esbuild.build({ + bundle: true, + external: entryPoint.exclude, + packages: 'external', // "external all the things", see https://esbuild.github.io/api/#packages + platform: 'neutral', // makes esm + format: 'esm', + plugins: [boilerplateTrimmer], + target: ['es2022'], + loader: { + '.ttf': 'file', + '.svg': 'file', + '.png': 'file', + '.sh': 'file', + }, + assetNames: 'media/[name]', // moves media assets into a sub-folder "media" + banner, + entryPoints: [ + { + in: path.join(REPO_ROOT_PATH, opts.src, `${entryPoint.name}.js`), + out: dest, + } + ], + outdir: path.join(REPO_ROOT_PATH, opts.src), + write: false, // enables res.outputFiles + metafile: true, // enables res.metafile + + }).then(res => { + for (const file of res.outputFiles) { + + let contents = file.contents; + + if (file.path.endsWith('.js')) { + + if (opts.fileContentMapper) { + // UGLY the fileContentMapper is per file but at this point we have all files + // bundled already. So, we call the mapper for the same contents but each file + // that has been included in the bundle... + let newText = file.text; + for (const input of Object.keys(res.metafile.inputs)) { + newText = opts.fileContentMapper(newText, input); + } + contents = Buffer.from(newText); + } + } + + files.push(new VinylFile({ + contents: Buffer.from(contents), + path: file.path, + base: path.join(REPO_ROOT_PATH, opts.src) + })); + } + }); + + // await task; // FORCE serial bundling (makes debugging easier) + tasks.push(task); + } + + await Promise.all(tasks); + return { files }; + }; + + bundleAsync().then((output) => { + + // bundle output (JS, CSS, SVG...) + es.readArray(output.files).pipe(bundlesStream); + + // forward all resources + gulp.src(opts.resources, { base: `${opts.src}`, allowEmpty: true }).pipe(resourcesStream); + }); + + const result = es.merge( + bundlesStream, + resourcesStream + ); + + return result + .pipe(sourcemaps.write('./', { + sourceRoot: undefined, + addComment: true, + includeContent: true + })) + .pipe(opts.languages && opts.languages.length ? processNlsFiles({ + out: opts.src, + fileHeader: opts.header || DEFAULT_FILE_HEADER, + languages: opts.languages + }) : es.through()); +} + export interface IOptimizeCommonJSTaskOpts { /** * The paths to consider for optimizing. @@ -291,8 +436,6 @@ export interface IOptimizeCommonJSTaskOpts { } function optimizeCommonJSTask(opts: IOptimizeCommonJSTaskOpts): NodeJS.ReadWriteStream { - const esbuild = require('esbuild') as typeof import('esbuild'); - const src = opts.src; const entryPoints = opts.entryPoints; @@ -360,9 +503,15 @@ export interface IOptimizeTaskOpts { export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { return function () { - const optimizers = [optimizeAMDTask(opts.amd)]; - if (opts.commonJS) { - optimizers.push(optimizeCommonJSTask(opts.commonJS)); + const optimizers: NodeJS.ReadWriteStream[] = []; + if (isESM('Running optimizer in ESM mode')) { + optimizers.push(optimizeESMTask(opts.amd, opts.commonJS)); + } else { + optimizers.push(optimizeAMDTask(opts.amd)); + + if (opts.commonJS) { + optimizers.push(optimizeCommonJSTask(opts.commonJS)); + } } if (opts.manual) { @@ -374,12 +523,10 @@ export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStr } export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => void { - const esbuild = require('esbuild') as typeof import('esbuild'); const sourceMappingURL = sourceMapBaseUrl ? ((f: any) => `${sourceMapBaseUrl}/${f.relative}.map`) : undefined; return cb => { const cssnano = require('cssnano') as typeof import('cssnano'); - const sourcemaps = require('gulp-sourcemaps') as typeof import('gulp-sourcemaps'); const svgmin = require('gulp-svgmin') as typeof import('gulp-svgmin'); const jsFilter = filter('**/*.js', { restore: true }); @@ -397,7 +544,7 @@ export function minifyTask(src: string, sourceMapBaseUrl?: string): (cb: any) => sourcemap: 'external', outdir: '.', platform: 'node', - target: ['esnext'], + target: ['es2022'], write: false }).then(res => { const jsFile = res.outputFiles.find(f => /\.js$/.test(f.path))!; diff --git a/build/lib/standalone.js b/build/lib/standalone.js index cf0e452aff3..78030842569 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -131,7 +131,7 @@ function createESMSourcesAndResources2(options) { } if (file === 'tsconfig.json') { const tsConfig = JSON.parse(fs.readFileSync(path.join(SRC_FOLDER, file)).toString()); - tsConfig.compilerOptions.module = 'es6'; + tsConfig.compilerOptions.module = 'es2022'; tsConfig.compilerOptions.outDir = path.join(path.relative(OUT_FOLDER, OUT_RESOURCES_FOLDER), 'vs').replace(/\\/g, '/'); write(getDestAbsoluteFilePath(file), JSON.stringify(tsConfig, null, '\t')); continue; diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index 9a65bfa7444..e1b9db65e12 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -157,7 +157,7 @@ export function createESMSourcesAndResources2(options: IOptions2): void { if (file === 'tsconfig.json') { const tsConfig = JSON.parse(fs.readFileSync(path.join(SRC_FOLDER, file)).toString()); - tsConfig.compilerOptions.module = 'es6'; + tsConfig.compilerOptions.module = 'es2022'; tsConfig.compilerOptions.outDir = path.join(path.relative(OUT_FOLDER, OUT_RESOURCES_FOLDER), 'vs').replace(/\\/g, '/'); write(getDestAbsoluteFilePath(file), JSON.stringify(tsConfig, null, '\t')); continue; diff --git a/build/lib/stylelint/vscode-known-variables.json b/build/lib/stylelint/vscode-known-variables.json index 8bca0f668d0..dbd1ecbf4db 100644 --- a/build/lib/stylelint/vscode-known-variables.json +++ b/build/lib/stylelint/vscode-known-variables.json @@ -35,13 +35,6 @@ "--vscode-button-secondaryForeground", "--vscode-button-secondaryHoverBackground", "--vscode-button-separator", - "--vscode-radio-inactiveForeground", - "--vscode-radio-inactiveBackground", - "--vscode-radio-inactiveBorder", - "--vscode-radio-activeForeground", - "--vscode-radio-activeBackground", - "--vscode-radio-activeBorder", - "--vscode-radio-inactiveHoverBackground", "--vscode-charts-blue", "--vscode-charts-foreground", "--vscode-charts-green", @@ -262,6 +255,10 @@ "--vscode-editorLightBulb-foreground", "--vscode-editorLightBulbAi-foreground", "--vscode-editorLightBulbAutoFix-foreground", + "--vscode-editorActionList-background", + "--vscode-editorActionList-foreground", + "--vscode-editorActionList-focusForeground", + "--vscode-editorActionList-focusBackground", "--vscode-editorLineNumber-activeForeground", "--vscode-editorLineNumber-dimmedForeground", "--vscode-editorLineNumber-foreground", @@ -346,7 +343,7 @@ "--vscode-icon-foreground", "--vscode-inlineChat-background", "--vscode-inlineChat-border", - "--vscode-inlineChat-regionHighlight", + "--vscode-inlineChat-foreground", "--vscode-inlineChat-shadow", "--vscode-inlineChatDiff-inserted", "--vscode-inlineChatDiff-removed", @@ -707,7 +704,21 @@ "--vscode-quickInputList-focusForeground", "--vscode-quickInputList-focusIconForeground", "--vscode-quickInputTitle-background", + "--vscode-radio-activeBackground", + "--vscode-radio-activeBorder", + "--vscode-radio-activeForeground", + "--vscode-radio-inactiveBackground", + "--vscode-radio-inactiveBorder", + "--vscode-radio-inactiveForeground", + "--vscode-radio-inactiveHoverBackground", "--vscode-sash-hoverBorder", + "--vscode-scm-historyGraph-green", + "--vscode-scm-historyGraph-historyItemGroupBase", + "--vscode-scm-historyGraph-historyItemGroupHoverLabelForeground", + "--vscode-scm-historyGraph-historyItemGroupLocal", + "--vscode-scm-historyGraph-historyItemGroupRemote", + "--vscode-scm-historyGraph-red", + "--vscode-scm-historyGraph-yellow", "--vscode-scm-historyItemAdditionsForeground", "--vscode-scm-historyItemDeletionsForeground", "--vscode-scm-historyItemSelectedStatisticsBorder", @@ -887,8 +898,10 @@ "--vscode-terminalCommandDecoration-defaultBackground", "--vscode-terminalCommandDecoration-errorBackground", "--vscode-terminalCommandDecoration-successBackground", + "--vscode-terminalCommandGuide-foreground", "--vscode-terminalCursor-background", "--vscode-terminalCursor-foreground", + "--vscode-terminalOverviewRuler-border", "--vscode-terminalOverviewRuler-cursorForeground", "--vscode-terminalOverviewRuler-findMatchForeground", "--vscode-terminalStickyScroll-background", @@ -987,6 +1000,7 @@ "--testMessageDecorationFontFamily", "--testMessageDecorationFontSize", "--title-border-bottom-color", + "--title-wco-width", "--vscode-chat-list-background", "--vscode-editorCodeLens-fontFamily", "--vscode-editorCodeLens-fontFamilyDefault", diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index c8e95511877..842f691af8f 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -100,24 +100,22 @@ function discoverAndReadFiles(ts, options) { options.entryPoints.forEach((entryPoint) => enqueue(entryPoint)); while (queue.length > 0) { const moduleId = queue.shift(); - const dts_filename = path.join(options.sourcesRoot, moduleId + '.d.ts'); + let redirectedModuleId = moduleId; + if (options.redirects[moduleId]) { + redirectedModuleId = options.redirects[moduleId]; + } + const dts_filename = path.join(options.sourcesRoot, redirectedModuleId + '.d.ts'); if (fs.existsSync(dts_filename)) { const dts_filecontents = fs.readFileSync(dts_filename).toString(); FILES[`${moduleId}.d.ts`] = dts_filecontents; continue; } - const js_filename = path.join(options.sourcesRoot, moduleId + '.js'); + const js_filename = path.join(options.sourcesRoot, redirectedModuleId + '.js'); if (fs.existsSync(js_filename)) { // This is an import for a .js file, so ignore it... continue; } - let ts_filename; - if (options.redirects[moduleId]) { - ts_filename = path.join(options.sourcesRoot, options.redirects[moduleId] + '.ts'); - } - else { - ts_filename = path.join(options.sourcesRoot, moduleId + '.ts'); - } + const ts_filename = path.join(options.sourcesRoot, redirectedModuleId + '.ts'); const ts_filecontents = fs.readFileSync(ts_filename).toString(); const info = ts.preProcessFile(ts_filecontents); for (let i = info.importedFiles.length - 1; i >= 0; i--) { diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 020e567eb72..d01b34d264f 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -155,25 +155,27 @@ function discoverAndReadFiles(ts: typeof import('typescript'), options: ITreeSha while (queue.length > 0) { const moduleId = queue.shift()!; - const dts_filename = path.join(options.sourcesRoot, moduleId + '.d.ts'); + let redirectedModuleId: string = moduleId; + if (options.redirects[moduleId]) { + redirectedModuleId = options.redirects[moduleId]; + } + + const dts_filename = path.join(options.sourcesRoot, redirectedModuleId + '.d.ts'); if (fs.existsSync(dts_filename)) { const dts_filecontents = fs.readFileSync(dts_filename).toString(); FILES[`${moduleId}.d.ts`] = dts_filecontents; continue; } - const js_filename = path.join(options.sourcesRoot, moduleId + '.js'); + + const js_filename = path.join(options.sourcesRoot, redirectedModuleId + '.js'); if (fs.existsSync(js_filename)) { // This is an import for a .js file, so ignore it... continue; } - let ts_filename: string; - if (options.redirects[moduleId]) { - ts_filename = path.join(options.sourcesRoot, options.redirects[moduleId] + '.ts'); - } else { - ts_filename = path.join(options.sourcesRoot, moduleId + '.ts'); - } + const ts_filename = path.join(options.sourcesRoot, redirectedModuleId + '.ts'); + const ts_filecontents = fs.readFileSync(ts_filename).toString(); const info = ts.preProcessFile(ts_filecontents); for (let i = info.importedFiles.length - 1; i >= 0; i--) { diff --git a/build/linux/debian/dep-lists.js b/build/linux/debian/dep-lists.js index 3a642a72725..3bb58fb1215 100644 --- a/build/linux/debian/dep-lists.js +++ b/build/linux/debian/dep-lists.js @@ -40,10 +40,8 @@ exports.referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', @@ -79,10 +77,8 @@ exports.referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', @@ -119,10 +115,8 @@ exports.referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', diff --git a/build/linux/debian/dep-lists.ts b/build/linux/debian/dep-lists.ts index 86d1de12216..e3d78d1139a 100644 --- a/build/linux/debian/dep-lists.ts +++ b/build/linux/debian/dep-lists.ts @@ -40,10 +40,8 @@ export const referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', @@ -79,10 +77,8 @@ export const referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', @@ -119,10 +115,8 @@ export const referenceGeneratedDepsByArch = { 'libexpat1 (>= 2.1~beta3)', 'libgbm1 (>= 17.1.0~rc2)', 'libglib2.0-0 (>= 2.37.3)', - 'libgssapi-krb5-2 (>= 1.17)', 'libgtk-3-0 (>= 3.9.10)', 'libgtk-3-0 (>= 3.9.10) | libgtk-4-1', - 'libkrb5-3 (>= 1.6.dfsg.2)', 'libnspr4 (>= 2:4.9-2~)', 'libnss3 (>= 2:3.30)', 'libnss3 (>= 3.26)', diff --git a/build/linux/dependencies-generator.js b/build/linux/dependencies-generator.js index 604094b52b6..ea58140f6c6 100644 --- a/build/linux/dependencies-generator.js +++ b/build/linux/dependencies-generator.js @@ -19,6 +19,7 @@ const types_2 = require("./rpm/types"); // which we don't need. // import product = require('../../product.json'); // --- End Positron -- +const esm_1 = require("../lib/esm"); // A flag that can easily be toggled. // Make sure to compile the build directory after toggling the value. // If false, we warn about new dependencies if they show up @@ -51,7 +52,8 @@ async function getDependencies(packageType, buildDir, applicationName, arch) { throw new Error('Invalid RPM arch string ' + arch); } // Get the files for which we want to find dependencies. - const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); + const canAsar = !(0, esm_1.isESM)('ASAR disabled in Linux builds'); // TODO@esm ASAR disabled in ESM + const nativeModulesPath = path.join(buildDir, 'resources', 'app', canAsar ? 'node_modules.asar.unpacked' : 'node_modules'); const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']); if (findResult.status) { console.error('Error finding files:'); diff --git a/build/linux/dependencies-generator.ts b/build/linux/dependencies-generator.ts index 20cc15c62e1..5ac87a2a1e2 100644 --- a/build/linux/dependencies-generator.ts +++ b/build/linux/dependencies-generator.ts @@ -19,6 +19,7 @@ import { isRpmArchString, RpmArchString } from './rpm/types'; // which we don't need. // import product = require('../../product.json'); // --- End Positron -- +import { isESM } from '../lib/esm'; // A flag that can easily be toggled. // Make sure to compile the build directory after toggling the value. @@ -55,7 +56,8 @@ export async function getDependencies(packageType: 'deb' | 'rpm', buildDir: stri } // Get the files for which we want to find dependencies. - const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked'); + const canAsar = !isESM('ASAR disabled in Linux builds'); // TODO@esm ASAR disabled in ESM + const nativeModulesPath = path.join(buildDir, 'resources', 'app', canAsar ? 'node_modules.asar.unpacked' : 'node_modules'); const findResult = spawnSync('find', [nativeModulesPath, '-name', '*.node']); if (findResult.status) { console.error('Error finding files:'); diff --git a/build/linux/rpm/dep-lists.js b/build/linux/rpm/dep-lists.js index 97984514511..fa393808c53 100644 --- a/build/linux/rpm/dep-lists.js +++ b/build/linux/rpm/dep-lists.js @@ -73,11 +73,7 @@ exports.referenceGeneratedDepsByArch = { 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', - 'libgssapi_krb5.so.2()(64bit)', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)(64bit)', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3()(64bit)', - 'libkrb5.so.3(krb5_3_MIT)(64bit)', 'libm.so.6()(64bit)', 'libm.so.6(GLIBC_2.2.5)(64bit)', 'libnspr4.so()(64bit)', @@ -166,12 +162,8 @@ exports.referenceGeneratedDepsByArch = { 'libgio-2.0.so.0', 'libglib-2.0.so.0', 'libgobject-2.0.so.0', - 'libgssapi_krb5.so.2', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)', 'libgtk-3.so.0', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3', - 'libkrb5.so.3(krb5_3_MIT)', 'libm.so.6', 'libm.so.6(GLIBC_2.4)', 'libnspr4.so', @@ -264,11 +256,7 @@ exports.referenceGeneratedDepsByArch = { 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', - 'libgssapi_krb5.so.2()(64bit)', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)(64bit)', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3()(64bit)', - 'libkrb5.so.3(krb5_3_MIT)(64bit)', 'libm.so.6()(64bit)', 'libm.so.6(GLIBC_2.17)(64bit)', 'libnspr4.so()(64bit)', diff --git a/build/linux/rpm/dep-lists.ts b/build/linux/rpm/dep-lists.ts index b79812784bf..9eed3a79f7e 100644 --- a/build/linux/rpm/dep-lists.ts +++ b/build/linux/rpm/dep-lists.ts @@ -72,11 +72,7 @@ export const referenceGeneratedDepsByArch = { 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', - 'libgssapi_krb5.so.2()(64bit)', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)(64bit)', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3()(64bit)', - 'libkrb5.so.3(krb5_3_MIT)(64bit)', 'libm.so.6()(64bit)', 'libm.so.6(GLIBC_2.2.5)(64bit)', 'libnspr4.so()(64bit)', @@ -165,12 +161,8 @@ export const referenceGeneratedDepsByArch = { 'libgio-2.0.so.0', 'libglib-2.0.so.0', 'libgobject-2.0.so.0', - 'libgssapi_krb5.so.2', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)', 'libgtk-3.so.0', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3', - 'libkrb5.so.3(krb5_3_MIT)', 'libm.so.6', 'libm.so.6(GLIBC_2.4)', 'libnspr4.so', @@ -263,11 +255,7 @@ export const referenceGeneratedDepsByArch = { 'libgio-2.0.so.0()(64bit)', 'libglib-2.0.so.0()(64bit)', 'libgobject-2.0.so.0()(64bit)', - 'libgssapi_krb5.so.2()(64bit)', - 'libgssapi_krb5.so.2(gssapi_krb5_2_MIT)(64bit)', 'libgtk-3.so.0()(64bit)', - 'libkrb5.so.3()(64bit)', - 'libkrb5.so.3(krb5_3_MIT)(64bit)', 'libm.so.6()(64bit)', 'libm.so.6(GLIBC_2.17)(64bit)', 'libnspr4.so()(64bit)', diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index a6eb3b7128f..ef5c2e39ae5 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -92,7 +92,7 @@ declare namespace monaco.editor { #includeAll(vs/editor/standalone/browser/standaloneEditor;languages.Token=>Token): #include(vs/editor/standalone/common/standaloneTheme): BuiltinTheme, IStandaloneThemeData, IColors #include(vs/editor/common/languages/supports/tokenization): ITokenThemeRule -#include(vs/editor/browser/services/webWorker): MonacoWebWorker, IWebWorkerOptions +#include(vs/editor/standalone/browser/standaloneWebWorker): MonacoWebWorker, IWebWorkerOptions #include(vs/editor/standalone/browser/standaloneCodeEditor): IActionDescriptor, IGlobalEditorOptions, IStandaloneEditorConstructionOptions, IStandaloneDiffEditorConstructionOptions, IStandaloneCodeEditor, IStandaloneDiffEditor export interface ICommandHandler { (...args: any[]): void; diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index dd9aba6bf53..2946d25245b 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -129,11 +129,6 @@ for (let dir of dirs) { } } - if (/^(.build\/distro\/npm\/)?remote/.test(dir) && process.platform === 'win32' && (process.arch === 'arm64' || process.env['npm_config_arch'] === 'arm64')) { - // windows arm: do not execute `yarn` on remote folder - continue; - } - let opts; if (dir === 'build') { diff --git a/build/npm/preinstall.js b/build/npm/preinstall.js index fdb01f579d6..f359215ec8e 100644 --- a/build/npm/preinstall.js +++ b/build/npm/preinstall.js @@ -73,9 +73,9 @@ function hasSupportedVisualStudioVersion() { const programFiles86Path = process.env['ProgramFiles(x86)']; const programFiles64Path = process.env['ProgramFiles']; + const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools', 'IntPreview']; if (programFiles64Path) { vsPath = `${programFiles64Path}/Microsoft Visual Studio/${version}`; - const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools']; if (vsTypes.some(vsType => fs.existsSync(path.join(vsPath, vsType)))) { availableVersions.push(version); break; @@ -84,7 +84,6 @@ function hasSupportedVisualStudioVersion() { if (programFiles86Path) { vsPath = `${programFiles86Path}/Microsoft Visual Studio/${version}`; - const vsTypes = ['Enterprise', 'Professional', 'Community', 'Preview', 'BuildTools']; if (vsTypes.some(vsType => fs.existsSync(path.join(vsPath, vsType)))) { availableVersions.push(version); break; @@ -123,19 +122,7 @@ function installHeaders() { cp.execFileSync(node_gyp, ['install', '--dist-url', local.disturl, local.target], { shell: true }); } - // Avoid downloading headers for Windows arm64 till we move to Nodejs v19 in remote - // which is the first official release with support for the architecture. Downloading - // the headers for older versions now redirect to https://origin.nodejs.org/404.html - // which causes checksum validation error in node-gyp. - // - // gyp http 200 https://origin.nodejs.org/404.html - // gyp WARN install got an error, rolling back install - // gyp ERR! install error - // gyp ERR! stack Error: win-arm64/node.lib local checksum 4c62bed7a032f7b36984321b7ffdd60b596fac870672037ff879ae9ac9548fb7 not match remote undefined - // - if (remote !== undefined && !versions.has(remote.target) && - process.env['npm_config_arch'] !== "arm64" && - process.arch !== "arm64") { + if (remote !== undefined && !versions.has(remote.target)) { // Both disturl and target come from a file checked into our repository cp.execFileSync(node_gyp, ['install', '--dist-url', remote.disturl, remote.target], { shell: true }); } diff --git a/build/package.json b/build/package.json index 1a73af91e6e..c93b66e03dc 100644 --- a/build/package.json +++ b/build/package.json @@ -20,6 +20,7 @@ "@types/gulp-gzip": "^0.0.31", "@types/gulp-json-editor": "^2.2.31", "@types/gulp-rename": "^0.0.33", + "@types/gulp-sort": "^2.0.4", "@types/gulp-sourcemaps": "^0.0.32", "@types/mime": "0.0.29", "@types/minimatch": "^3.0.3", @@ -44,6 +45,7 @@ "esbuild": "0.23.0", "extract-zip": "^2.0.1", "gulp-merge-json": "^2.1.1", + "gulp-sort": "^2.0.0", "jsonc-parser": "^2.3.0", "mime": "^1.4.1", "mkdirp": "^1.0.4", @@ -51,7 +53,7 @@ "ternary-stream": "^3.0.0", "through2": "^4.0.2", "tmp": "^0.2.1", - "vscode-universal-bundler": "^0.1.0", + "vscode-universal-bundler": "^0.1.3", "workerpool": "^6.4.0", "yauzl": "^2.10.0" }, diff --git a/build/secrets/.secrets.baseline b/build/secrets/.secrets.baseline index 54b8c17f635..b4050b4ef4e 100644 --- a/build/secrets/.secrets.baseline +++ b/build/secrets/.secrets.baseline @@ -94,6 +94,10 @@ "path": "detect_secrets.filters.common.is_baseline_file", "filename": "build/secrets/.secrets.baseline" }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, { "path": "detect_secrets.filters.heuristic.is_indirect_reference" }, @@ -199,7 +203,7 @@ "filename": "build/azure-pipelines/darwin/product-build-darwin.yml", "hashed_secret": "d8368fc8fec27a14a70083cc2cd6d959085086a9", "is_verified": false, - "line_number": 33, + "line_number": 36, "is_secret": false } ], @@ -219,7 +223,7 @@ "filename": "build/azure-pipelines/linux/product-build-linux-legacy-server.yml", "hashed_secret": "6bca595fb7e6690f8bacc9e0c1e056cd60e4b7cb", "is_verified": false, - "line_number": 23, + "line_number": 26, "is_secret": false } ], @@ -229,7 +233,7 @@ "filename": "build/azure-pipelines/linux/product-build-linux.yml", "hashed_secret": "256e334e9cc8b59bb08501110e1c729c9b2edec4", "is_verified": false, - "line_number": 35, + "line_number": 38, "is_secret": false } ], @@ -239,7 +243,7 @@ "filename": "build/azure-pipelines/product-compile.yml", "hashed_secret": "6bca595fb7e6690f8bacc9e0c1e056cd60e4b7cb", "is_verified": false, - "line_number": 20, + "line_number": 23, "is_secret": false } ], @@ -253,16 +257,6 @@ "is_secret": false } ], - "build/azure-pipelines/sdl-scan.yml": [ - { - "type": "Secret Keyword", - "filename": "build/azure-pipelines/sdl-scan.yml", - "hashed_secret": "6bca595fb7e6690f8bacc9e0c1e056cd60e4b7cb", - "is_verified": false, - "line_number": 27, - "is_secret": false - } - ], "build/azure-pipelines/web/product-build-web.yml": [ { "type": "Secret Keyword", @@ -279,7 +273,17 @@ "filename": "build/azure-pipelines/win32/product-build-win32.yml", "hashed_secret": "256e334e9cc8b59bb08501110e1c729c9b2edec4", "is_verified": false, - "line_number": 40, + "line_number": 43, + "is_secret": false + } + ], + "build/azure-pipelines/win32/sdl-scan-win32.yml": [ + { + "type": "Secret Keyword", + "filename": "build/azure-pipelines/win32/sdl-scan-win32.yml", + "hashed_secret": "6bca595fb7e6690f8bacc9e0c1e056cd60e4b7cb", + "is_verified": false, + "line_number": 26, "is_secret": false } ], @@ -543,7 +547,7 @@ { "type": "Hex High Entropy String", "filename": "package.json", - "hashed_secret": "328c19cf09eea1574843068faa2eefb00330fd9a", + "hashed_secret": "c635602d4b9175ddc1638f98082d7703c4b80f2b", "is_verified": false, "line_number": 4, "is_secret": false @@ -561,7 +565,7 @@ { "type": "Hex High Entropy String", "filename": "product.json", - "hashed_secret": "097ac5d8527520960630a51a453626dd781609cc", + "hashed_secret": "1b012f829c16ba44801ba646cd54b79048d53ae9", "is_verified": false, "line_number": 59, "is_secret": false @@ -573,6 +577,14 @@ "is_verified": false, "line_number": 75, "is_secret": false + }, + { + "type": "Hex High Entropy String", + "filename": "product.json", + "hashed_secret": "0570cc883d4d190824469556cde84c3f48169c94", + "is_verified": false, + "line_number": 229, + "is_secret": false } ], "scripts/playground-server.ts": [ @@ -591,7 +603,7 @@ "filename": "src/bootstrap-window.js", "hashed_secret": "b6cb3f02e20180320687f4905a9c795d72e0ad3a", "is_verified": false, - "line_number": 151, + "line_number": 133, "is_secret": false } ], @@ -888,12 +900,28 @@ } ], "src/vs/server/node/webClientServer.ts": [ + { + "type": "Base64 High Entropy String", + "filename": "src/vs/server/node/webClientServer.ts", + "hashed_secret": "66e26ed510af41f1d322d1ebda4389302f4a03c7", + "is_verified": false, + "line_number": 445, + "is_secret": false + }, { "type": "Base64 High Entropy String", "filename": "src/vs/server/node/webClientServer.ts", "hashed_secret": "f769de45d1747b634dfe3d7eb842f6967c4c5e98", "is_verified": false, - "line_number": 386, + "line_number": 445, + "is_secret": false + }, + { + "type": "Base64 High Entropy String", + "filename": "src/vs/server/node/webClientServer.ts", + "hashed_secret": "93f2efffc36c6e096cdb21d6aadb7087dc0d7478", + "is_verified": false, + "line_number": 452, "is_secret": false } ], @@ -1819,7 +1847,7 @@ { "type": "Base64 High Entropy String", "filename": "src/vs/workbench/contrib/webview/browser/pre/index.html", - "hashed_secret": "d2ca05efa3869fb799c6229cc3c55a3505bb9c1c", + "hashed_secret": "18e28cb104e16a9281ba04f02b3d657de3110053", "is_verified": false, "line_number": 9, "is_secret": false @@ -1831,7 +1859,17 @@ "filename": "src/vs/workbench/services/environment/browser/environmentService.ts", "hashed_secret": "3a8f125da17a2c187d430daf0045e0fdfa707bdd", "is_verified": false, - "line_number": 234, + "line_number": 273, + "is_secret": false + } + ], + "src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html": [ + { + "type": "Base64 High Entropy String", + "filename": "src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.esm.html", + "hashed_secret": "b6d602bc7fc2b53ca2a176860f06c731ff0dfaf4", + "is_verified": false, + "line_number": 7, "is_secret": false } ], @@ -1839,9 +1877,9 @@ { "type": "Base64 High Entropy String", "filename": "src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html", - "hashed_secret": "f769de45d1747b634dfe3d7eb842f6967c4c5e98", + "hashed_secret": "9d2f1684b9408fdc43d928422965a743ef0f2e9e", "is_verified": false, - "line_number": 7, + "line_number": 8, "is_secret": false } ], @@ -1874,5 +1912,5 @@ } ] }, - "generated_at": "2024-08-08T06:50:45Z" + "generated_at": "2024-09-11T23:58:52Z" } diff --git a/build/yarn.lock b/build/yarn.lock index 93475761437..1e3928aa0cf 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -483,6 +483,14 @@ dependencies: "@types/node" "*" +"@types/gulp-sort@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/gulp-sort/-/gulp-sort-2.0.4.tgz#60625bf608dbac8f03644c6785d25c616f1b7d8c" + integrity sha512-HUHxH+oMox1ct0SnxPqCXBni0MSws1ygcSAoLO4ISRmR/UuvNIz40rgNveZxwxQk+p78kw09z/qKQkgKJmNUOQ== + dependencies: + "@types/gulp-util" "*" + "@types/node" "*" + "@types/gulp-sourcemaps@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/gulp-sourcemaps/-/gulp-sourcemaps-0.0.32.tgz#e79ee617e0cb15729874be4533fe59c07793a175" @@ -490,6 +498,16 @@ dependencies: "@types/node" "*" +"@types/gulp-util@*": + version "3.0.41" + resolved "https://registry.yarnpkg.com/@types/gulp-util/-/gulp-util-3.0.41.tgz#52868a6f8b6af55a099fe48ea20736833c02bed4" + integrity sha512-BK0kJZ8euQNlISsmD6mBr/1RZkB0mljdtBsz2usv+QHPV10alH2AJw5p05S9LU6S+VdTjbFmGU0OxpH++2W9/Q== + dependencies: + "@types/node" "*" + "@types/through2" "*" + "@types/vinyl" "*" + chalk "^2.2.0" + "@types/gulp@^4.0.17": version "4.0.17" resolved "https://registry.yarnpkg.com/@types/gulp/-/gulp-4.0.17.tgz#b314c3762d08d8d69b7c0b86f78d069bafd65009" @@ -591,6 +609,13 @@ "@types/glob" "*" "@types/node" "*" +"@types/through2@*": + version "2.0.41" + resolved "https://registry.yarnpkg.com/@types/through2/-/through2-2.0.41.tgz#3e5e1720d71ffdfa03c22f2aad6593d12a47034f" + integrity sha512-ryQ0tidWkb1O1JuYvWKyMLYEtOWDqF5mHerJzKz/gQpoAaJq2l/dsMPBF0B5BNVT34rbARYJ5/tsZwLfUi2kwQ== + dependencies: + "@types/node" "*" + "@types/through2@^2.0.36": version "2.0.36" resolved "https://registry.yarnpkg.com/@types/through2/-/through2-2.0.36.tgz#35fda0db635827d44c0e08e2c94653e647574a00" @@ -930,7 +955,7 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.2" -chalk@^2.4.2: +chalk@^2.2.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1546,6 +1571,13 @@ gulp-merge-json@^2.1.1: through "^2.3.8" vinyl "^2.1.0" +gulp-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-sort/-/gulp-sort-2.0.0.tgz#c6762a2f1f0de0a3fc595a21599d3fac8dba1aca" + integrity sha512-MyTel3FXOdh1qhw1yKhpimQrAmur9q1X0ZigLmCOxouQD+BD3za9/89O+HfbgBQvvh4igEbp0/PUWO+VqGYG1g== + dependencies: + through2 "^2.0.1" + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2255,6 +2287,19 @@ readable-stream@^2.0.2, readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdirp@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" @@ -2505,6 +2550,14 @@ ternary-stream@^3.0.0: merge-stream "^2.0.0" through2 "^3.0.1" +through2@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + through2@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" @@ -2681,10 +2734,10 @@ vscode-gulp-watch@^5.0.3: vinyl "^2.2.0" vinyl-file "^3.0.0" -vscode-universal-bundler@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/vscode-universal-bundler/-/vscode-universal-bundler-0.1.0.tgz#1a03d1d16c6ea5065318fafbc2a554b7c2f3bd32" - integrity sha512-wtT9IZ/fqIZSirY6cxElu8a6WpNaOjgQjjazt85lMCWBuF/tWVw5nRYX67pTVsUyi6kzQaIvfyyIvxVbBpetBA== +vscode-universal-bundler@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/vscode-universal-bundler/-/vscode-universal-bundler-0.1.3.tgz#bd223e61ca0ed1d8ebb1c023d5ad99aab92c3d35" + integrity sha512-USXJqgD+ySROqgjl+KrGjlF7MvNnqsI6my1kUOsAXARmNqBjXk38w8g2BF6PEXVOYOQ+npRcTA7athXNU4Jjog== dependencies: "@electron/asar" "^3.2.7" "@malept/cross-spawn-promise" "^2.0.0" @@ -2747,6 +2800,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" diff --git a/cglicenses.json b/cglicenses.json index 268a7e1dd1b..1919c9d293c 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -40,12 +40,6 @@ "Copyright (c) Microsoft Corporation. All rights reserved." ] }, - { - "name": "big-integer", - "prependLicenseText": [ - "Copyright released to public domain" - ] - }, { // Reason: The license cannot be found by the tool due to access controls on the repository "name": "vscode-tas-client", diff --git a/cgmanifest.json b/cgmanifest.json index aa06f8323b0..dcb4791c791 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -516,11 +516,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "fe0f08a5dd68fd72b1652adaa51ab07a4b09f847" + "commitHash": "a407d1f0b3669cc82c755700f0d500fb27cc39ea" } }, "isOnlyProductionDependency": true, - "version": "20.14.0" + "version": "20.15.1" }, { "component": { @@ -528,12 +528,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "91de7d0f13208891c5604e00ccd18e4f6826653b" + "commitHash": "ff3d3e69443c1c8939c9ba2d10d40cb65f3ff278" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "30.1.2" + "version": "30.4.0" }, { "component": { @@ -732,6 +732,39 @@ "SOFTWARE." ], "license": "MIT" + }, + { + "component": { + "type": "npm", + "npm": { + "name": "cacheable-request", + "version": "7.0.4" + } + }, + "licenseDetail": [ + "Copyright (c) cacheable-request authors", + "", + "MIT License", + "", + "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." + ], + "license": "MIT" } ], "version": 1 diff --git a/cli/ThirdPartyNotices.txt b/cli/ThirdPartyNotices.txt index 8d04738ba05..4a58801fa12 100644 --- a/cli/ThirdPartyNotices.txt +++ b/cli/ThirdPartyNotices.txt @@ -22,31 +22,16 @@ required to debug changes to any libraries licensed under the GNU Lesser General addr2line 0.21.0 - Apache-2.0 OR MIT https://github.com/gimli-rs/addr2line -Copyright (c) 2016-2018 The gimli Developers +Licensed under either of -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: + * Apache License, Version 2.0 ([`LICENSE-APACHE`](./LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([`LICENSE-MIT`](./LICENSE-MIT) or https://opensource.org/licenses/MIT) -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. +at your option. -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. +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. --------------------------------------------------------- --------------------------------------------------------- @@ -292,27 +277,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. async-broadcast 0.5.1 - MIT OR Apache-2.0 https://github.com/smol-rs/async-broadcast -The MIT License (MIT) - -Copyright (c) 2020 Yoshua Wuyts - -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: + +Licensed under either of Apache License, Version +2.0 (LICENSE-APACHE) or MIT license (LICENSE-MIT) at your option. + -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. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + --------------------------------------------------------- --------------------------------------------------------- @@ -320,29 +296,18 @@ SOFTWARE. async-channel 2.3.1 - Apache-2.0 OR MIT https://github.com/smol-rs/async-channel -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: +Licensed under either of -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -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. +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. --------------------------------------------------------- --------------------------------------------------------- @@ -382,29 +347,18 @@ async-lock 2.8.0 - Apache-2.0 OR MIT async-lock 3.3.0 - Apache-2.0 OR MIT https://github.com/smol-rs/async-lock -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: +Licensed under either of -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -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. +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. --------------------------------------------------------- --------------------------------------------------------- @@ -412,29 +366,18 @@ DEALINGS IN THE SOFTWARE. async-process 1.8.1 - Apache-2.0 OR MIT https://github.com/smol-rs/async-process -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: +Licensed under either of -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -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. +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. --------------------------------------------------------- --------------------------------------------------------- @@ -442,29 +385,13 @@ DEALINGS IN THE SOFTWARE. async-recursion 1.1.1 - MIT OR Apache-2.0 https://github.com/dcchut/async-recursion -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. +Licensed under either of + * Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or ) + * MIT license + ([LICENSE-MIT](LICENSE-MIT) or ) -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. +at your option. --------------------------------------------------------- --------------------------------------------------------- @@ -502,29 +429,18 @@ DEALINGS IN THE SOFTWARE. async-task 4.7.1 - Apache-2.0 OR MIT https://github.com/smol-rs/async-task -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: +Licensed under either of -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) -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. +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. --------------------------------------------------------- --------------------------------------------------------- @@ -4896,7 +4812,7 @@ OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -openssl 0.10.64 - Apache-2.0 +openssl 0.10.66 - Apache-2.0 https://github.com/sfackler/rust-openssl Copyright 2011-2017 Google Inc. @@ -4975,7 +4891,7 @@ DEALINGS IN THE SOFTWARE. --------------------------------------------------------- -openssl-sys 0.9.102 - MIT +openssl-sys 0.9.103 - MIT https://github.com/sfackler/rust-openssl The MIT License (MIT) @@ -10791,33 +10707,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI zbus 3.15.2 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- --------------------------------------------------------- @@ -10825,33 +10715,7 @@ DEALINGS IN THE SOFTWARE. zbus_macros 3.15.2 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- --------------------------------------------------------- @@ -10859,33 +10723,7 @@ DEALINGS IN THE SOFTWARE. zbus_names 2.6.1 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- --------------------------------------------------------- @@ -10978,33 +10816,7 @@ licences; see files named LICENSE.*.txt for details. zvariant 3.15.2 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- --------------------------------------------------------- @@ -11012,33 +10824,7 @@ DEALINGS IN THE SOFTWARE. zvariant_derive 3.15.2 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- --------------------------------------------------------- @@ -11046,31 +10832,5 @@ DEALINGS IN THE SOFTWARE. zvariant_utils 1.0.1 - MIT https://github.com/dbus2/zbus/ -The MIT License (MIT) - -Copyright (c) 2024 Zeeshan Ali Khan & zbus 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. +LICENSE-MIT --------------------------------------------------------- \ No newline at end of file diff --git a/cli/src/commands/args.rs b/cli/src/commands/args.rs index 05e22e0cfb3..101f1eac29f 100644 --- a/cli/src/commands/args.rs +++ b/cli/src/commands/args.rs @@ -230,8 +230,8 @@ pub struct CommandShellArgs { #[clap(long)] pub on_socket: bool, /// Listen on a host/port instead of stdin/stdout. - #[clap(long, num_args = 0..=1, default_missing_value = "0")] - pub on_port: Option, + #[clap(long, num_args = 0..=2, default_missing_value = "0")] + pub on_port: Vec, /// Listen on a host/port instead of stdin/stdout. #[clap[long]] pub on_host: Option, diff --git a/cli/src/commands/tunnels.rs b/cli/src/commands/tunnels.rs index 688f603f593..2d0014bca55 100644 --- a/cli/src/commands/tunnels.rs +++ b/cli/src/commands/tunnels.rs @@ -155,43 +155,52 @@ pub async fn command_shell(ctx: CommandContext, args: CommandShellArgs) -> Resul code_server_args: (&ctx.args).into(), }; - let mut listener: Box = match (args.on_port, &args.on_host, args.on_socket) - { - (_, _, true) => { - let socket = get_socket_name(); - let listener = listen_socket_rw_stream(&socket) - .await - .map_err(|e| wrap(e, "error listening on socket"))?; - - params - .log - .result(format!("Listening on {}", socket.display())); - - Box::new(listener) - } - (Some(_), _, _) | (_, Some(_), _) => { - let addr = SocketAddr::new( - args.on_host + let mut listener: Box = + match (args.on_port.first(), &args.on_host, args.on_socket) { + (_, _, true) => { + let socket = get_socket_name(); + let listener = listen_socket_rw_stream(&socket) + .await + .map_err(|e| wrap(e, "error listening on socket"))?; + + params + .log + .result(format!("Listening on {}", socket.display())); + + Box::new(listener) + } + (Some(_), _, _) | (_, Some(_), _) => { + let host = args + .on_host .as_ref() .map(|h| h.parse().map_err(CodeError::InvalidHostAddress)) - .unwrap_or(Ok(IpAddr::V4(Ipv4Addr::LOCALHOST)))?, - args.on_port.unwrap_or_default(), - ); - let listener = tokio::net::TcpListener::bind(addr) - .await - .map_err(|e| wrap(e, "error listening on port"))?; - - params - .log - .result(format!("Listening on {}", listener.local_addr().unwrap())); - - Box::new(listener) - } - _ => { - serve_stream(tokio::io::stdin(), tokio::io::stderr(), params).await; - return Ok(0); - } - }; + .unwrap_or(Ok(IpAddr::V4(Ipv4Addr::LOCALHOST)))?; + + let lower_port = args.on_port.first().copied().unwrap_or_default(); + let port_no = if let Some(upper) = args.on_port.get(1) { + find_unused_port(&host, lower_port, *upper) + .await + .unwrap_or_default() + } else { + lower_port + }; + + let addr = SocketAddr::new(host, port_no); + let listener = tokio::net::TcpListener::bind(addr) + .await + .map_err(|e| wrap(e, "error listening on port"))?; + + params + .log + .result(format!("Listening on {}", listener.local_addr().unwrap())); + + Box::new(listener) + } + _ => { + serve_stream(tokio::io::stdin(), tokio::io::stderr(), params).await; + return Ok(0); + } + }; let mut servers = FuturesUnordered::new(); @@ -216,6 +225,21 @@ pub async fn command_shell(ctx: CommandContext, args: CommandShellArgs) -> Resul } } +async fn find_unused_port(host: &IpAddr, start_port: u16, end_port: u16) -> Option { + for port in start_port..=end_port { + if is_port_available(*host, port).await { + return Some(port); + } + } + None +} + +async fn is_port_available(host: IpAddr, port: u16) -> bool { + tokio::net::TcpListener::bind(SocketAddr::new(host, port)) + .await + .is_ok() +} + pub async fn service( ctx: CommandContext, service_args: TunnelServiceSubCommands, diff --git a/cli/src/update_service.rs b/cli/src/update_service.rs index 4bec13d6e86..90339148188 100644 --- a/cli/src/update_service.rs +++ b/cli/src/update_service.rs @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -use std::{ffi::OsStr, fmt, path::Path}; +use std::{fmt, path::Path}; use serde::{Deserialize, Serialize}; @@ -11,10 +11,11 @@ use crate::{ constants::VSCODE_CLI_UPDATE_ENDPOINT, debug, log, options, spanf, util::{ - errors::{AnyError, CodeError, WrappedError}, + errors::{wrap, AnyError, CodeError, WrappedError}, http::{BoxedHttp, SimpleResponse}, io::ReportCopyProgress, - tar, zipper, + tar::{self, has_gzip_header}, + zipper, }, }; @@ -178,10 +179,10 @@ pub fn unzip_downloaded_release( where T: ReportCopyProgress, { - if compressed_file.extension() == Some(OsStr::new("zip")) { - zipper::unzip_file(compressed_file, target_dir, reporter) - } else { - tar::decompress_tarball(compressed_file, target_dir, reporter) + match has_gzip_header(compressed_file) { + Ok((f, true)) => tar::decompress_tarball(f, target_dir, reporter), + Ok((f, false)) => zipper::unzip_file(f, target_dir, reporter), + Err(e) => Err(wrap(e, "error checking for gzip header")), } } @@ -249,7 +250,7 @@ impl Platform { Platform::DarwinARM64 => "server-darwin-arm64", Platform::WindowsX64 => "server-win32-x64", Platform::WindowsX86 => "server-win32", - Platform::WindowsARM64 => "server-win32-x64", // we don't publish an arm64 server build yet + Platform::WindowsARM64 => "server-win32-arm64", } .to_owned() } diff --git a/cli/src/util/tar.rs b/cli/src/util/tar.rs index fe4d4269700..10577140325 100644 --- a/cli/src/util/tar.rs +++ b/cli/src/util/tar.rs @@ -5,8 +5,8 @@ use crate::util::errors::{wrap, WrappedError}; use flate2::read::GzDecoder; -use std::fs; -use std::io::Seek; +use std::fs::{self, File}; +use std::io::{Read, Seek}; use std::path::{Path, PathBuf}; use tar::Archive; @@ -57,16 +57,13 @@ fn should_skip_first_segment(file: &fs::File) -> Result<(bool, u64), WrappedErro } pub fn decompress_tarball( - path: &Path, + mut tar_gz: File, parent_path: &Path, mut reporter: T, ) -> Result<(), WrappedError> where T: ReportCopyProgress, { - let mut tar_gz = fs::File::open(path) - .map_err(|e| wrap(e, format!("error opening file {}", path.display())))?; - let (skip_first, num_entries) = should_skip_first_segment(&tar_gz)?; let report_progress_every = num_entries / 20; let mut entries_so_far = 0; @@ -81,7 +78,7 @@ where let mut archive = Archive::new(tar); archive .entries() - .map_err(|e| wrap(e, format!("error opening archive {}", path.display())))? + .map_err(|e| wrap(e, "error opening archive"))? .filter_map(|e| e.ok()) .try_for_each::<_, Result<_, WrappedError>>(|mut entry| { // approximate progress based on where we are in the archive: @@ -118,3 +115,13 @@ where Ok(()) } + +pub fn has_gzip_header(path: &Path) -> std::io::Result<(File, bool)> { + let mut file = fs::File::open(path)?; + let mut header = [0; 2]; + let _ = file.read_exact(&mut header); + + file.rewind()?; + + Ok((file, header[0] == 0x1f && header[1] == 0x8b)) +} diff --git a/cli/src/util/zipper.rs b/cli/src/util/zipper.rs index 69bcf2d23f6..5521fa42c54 100644 --- a/cli/src/util/zipper.rs +++ b/cli/src/util/zipper.rs @@ -44,15 +44,12 @@ fn should_skip_first_segment(archive: &mut ZipArchive) -> bool { archive.len() > 1 // prefix removal is invalid if there's only a single file } -pub fn unzip_file(path: &Path, parent_path: &Path, mut reporter: T) -> Result<(), WrappedError> +pub fn unzip_file(file: File, parent_path: &Path, mut reporter: T) -> Result<(), WrappedError> where T: ReportCopyProgress, { - let file = fs::File::open(path) - .map_err(|e| wrap(e, format!("unable to open file {}", path.display())))?; - - let mut archive = zip::ZipArchive::new(file) - .map_err(|e| wrap(e, format!("failed to open zip archive {}", path.display())))?; + let mut archive = + zip::ZipArchive::new(file).map_err(|e| wrap(e, "failed to open zip archive"))?; let skip_segments_no = usize::from(should_skip_first_segment(&mut archive)); let report_progress_every = archive.len() / 20; diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 57cbba323a4..10cbd954154 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -997,7 +997,7 @@ ] }, "dependencies": { - "vscode-languageclient": "^10.0.0-next.8", + "vscode-languageclient": "10.0.0-next.8", "vscode-uri": "^3.0.8" }, "devDependencies": { diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index fe4f64d7c01..329fe57fc57 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -11,8 +11,8 @@ "browser": "./dist/browser/cssServerMain", "dependencies": { "@vscode/l10n": "^0.0.18", - "vscode-css-languageservice": "^6.3.0", - "vscode-languageserver": "^10.0.0-next.6", + "vscode-css-languageservice": "^6.3.1", + "vscode-languageserver": "10.0.0-next.6", "vscode-uri": "^3.0.8" }, "devDependencies": { diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index 59033f770c1..f59aed24630 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -24,13 +24,13 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -vscode-css-languageservice@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.3.0.tgz#51724d193d19b1a9075b1cef5cfeea6a555d2aa4" - integrity sha512-nU92imtkgzpCL0xikrIb8WvedV553F2BENzgz23wFuok/HLN5BeQmroMy26pUwFxV2eV8oNRmYCUv8iO7kSMhw== +vscode-css-languageservice@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.3.1.tgz#56733c90686db56855ccc156a534a68b8c1f2187" + integrity sha512-1BzTBuJfwMc3A0uX4JBdJgoxp74cjj4q2mDJdp49yD/GuAq4X0k5WtK6fNcMYr+FfJ9nqgR6lpfCSZDkARJ5qQ== dependencies: "@vscode/l10n" "^0.0.18" - vscode-languageserver-textdocument "^1.0.11" + vscode-languageserver-textdocument "^1.0.12" vscode-languageserver-types "3.17.5" vscode-uri "^3.0.8" @@ -47,10 +47,10 @@ vscode-languageserver-protocol@3.17.6-next.6: vscode-jsonrpc "9.0.0-next.4" vscode-languageserver-types "3.17.6-next.4" -vscode-languageserver-textdocument@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" - integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== +vscode-languageserver-textdocument@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== vscode-languageserver-types@3.17.5: version "3.17.5" @@ -62,7 +62,7 @@ vscode-languageserver-types@3.17.6-next.4: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.6-next.4.tgz#6670939eb98f00aa7b05021dc3dd7fe9aa4453ea" integrity sha512-SeJTpH/S14EbxOAVaOUoGVqPToqpRTld5QO5Ghig3AlbFJTFF9Wu7srHMfa85L0SX1RYAuuCSFKJVVCxDIk1/Q== -vscode-languageserver@^10.0.0-next.6: +vscode-languageserver@10.0.0-next.6: version "10.0.0-next.6" resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-10.0.0-next.6.tgz#0db118a93fe010c6b40cd04e91a15d09e7b60b60" integrity sha512-0Lh1nhQfSxo5Ob+ayYO1QTIsDix2/Lc72Urm1KZrCFxK5zIFYaEh3QFeM9oZih4Rzs0ZkQPXXnoHtpvs5GT+Zw== diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index eef1c9ab57d..28dc1c05f96 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -52,7 +52,7 @@ vscode-jsonrpc@9.0.0-next.4: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0-next.4.tgz#ba403ddb3b82ca578179963dbe08e120a935f50d" integrity sha512-zSVIr58lJSMYKIsZ5P7GtBbv1eEx25eNyOf0NmEzxmn1GhUNJAVAb5hkA1poKUwj1FRMwN6CeyWxZypmr8SsQQ== -vscode-languageclient@^10.0.0-next.8: +vscode-languageclient@10.0.0-next.8: version "10.0.0-next.8" resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-10.0.0-next.8.tgz#5afa0ced3b2ac68d31cc1c48edc4f289744542a0" integrity sha512-D9inIHgqKayO9Tv0MeLb3XIL76yTuWmKdHqcGZKzjtQrMGJgASJDYWTapu+yAjEpDp0gmVOaCYyIlLB86ncDoQ== diff --git a/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json index 0b3c5d112e5..f10f9ca661a 100644 --- a/extensions/fsharp/cgmanifest.json +++ b/extensions/fsharp/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "ionide/ionide-fsgrammar", "repositoryUrl": "https://github.com/ionide/ionide-fsgrammar", - "commitHash": "0100f551f6c32598a58aba97344bf828673fec7a" + "commitHash": "7d1b695da917dc4c7a0f7fb4683f42da208f87a2" } }, "license": "MIT", diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 7806c100eae..41436335cdc 100644 --- a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json +++ b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json @@ -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/ionide/ionide-fsgrammar/commit/0100f551f6c32598a58aba97344bf828673fec7a", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/7d1b695da917dc4c7a0f7fb4683f42da208f87a2", "name": "fsharp", "scopeName": "source.fsharp", "patterns": [ @@ -841,7 +841,7 @@ "name": "keyword.symbol.fsharp" } }, - "end": "(\\)\\s*(([?[:alpha:]0-9'`^._ ]+))+)", + "end": "(\\)\\s*(([?[:alpha:]0-9'`^._ ]+))*)", "endCaptures": { "1": { "name": "keyword.symbol.fsharp" diff --git a/extensions/git/package.json b/extensions/git/package.json index fc0002a6313..6bf280b95da 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -19,6 +19,7 @@ "contribSourceControlHistoryItemChangesMenu", "contribSourceControlHistoryItemGroupMenu", "contribSourceControlHistoryItemMenu", + "contribSourceControlHistoryTitleMenu", "contribSourceControlInputBoxMenu", "contribSourceControlTitleMenu", "contribViewsWelcome", @@ -35,7 +36,6 @@ "scmValidation", "tabInputMultiDiff", "tabInputTextMerge", - "terminalShellIntegration", "timeline" ], "categories": [ @@ -1936,6 +1936,28 @@ "group": "1_modification@3" } ], + "scm/history/title": [ + { + "command": "git.fetchRef", + "group": "navigation@1", + "when": "scmProvider == git && scmHistoryItemGroupHasRemote" + }, + { + "command": "git.pullRef", + "group": "navigation@2", + "when": "scmProvider == git && scmHistoryItemGroupHasRemote" + }, + { + "command": "git.pushRef", + "when": "scmProvider == git && scmHistoryItemGroupHasRemote", + "group": "navigation@3" + }, + { + "command": "git.publish", + "when": "scmProvider == git && !scmHistoryItemGroupHasRemote", + "group": "navigation@3" + } + ], "scm/historyItemChanges/title": [ { "command": "git.fetchRef", diff --git a/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index f94ecbab7b0..332c328b2d1 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -322,6 +322,10 @@ export class ApiImpl implements API { } async openRepository(root: Uri): Promise { + if (root.scheme !== 'file') { + return null; + } + await this._model.openRepository(root.fsPath); return this.getRepository(root) || null; } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 2abbeaaa14e..17dd192ed95 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -147,6 +147,7 @@ export interface LogOptions { readonly author?: string; readonly refNames?: string[]; readonly maxParents?: number; + readonly skip?: number; } export interface CommitOptions { diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 957f447e8c2..9940ae535c7 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1062,6 +1062,7 @@ export interface PullOptions { } export class Repository { + private _isUsingRefTable = false; constructor( private _git: Git, @@ -1169,6 +1170,10 @@ export class Repository { args.push(`--max-parents=${options.maxParents}`); } + if (typeof options?.skip === 'number') { + args.push(`--skip=${options.skip}`); + } + if (options?.refNames) { args.push('--topo-order'); args.push('--decorate=full'); @@ -1506,6 +1511,21 @@ export class Repository { return parseGitChanges(this.repositoryRoot, gitResult.stdout); } + async diffTrees(treeish1: string, treeish2?: string): Promise { + const args = ['diff-tree', '-r', '--name-status', '-z', '--diff-filter=ADMR', treeish1]; + + if (treeish2) { + args.push(treeish2); + } + + const gitResult = await this.exec(args); + if (gitResult.exitCode) { + return []; + } + + return parseGitChanges(this.repositoryRoot, gitResult.stdout); + } + async getMergeBase(ref1: string, ref2: string, ...refs: string[]): Promise { try { const args = ['merge-base']; @@ -2315,13 +2335,25 @@ export class Repository { } async getHEAD(): Promise { - try { - // Attempt to parse the HEAD file - const result = await this.getHEADFS(); - return result; - } - catch (err) { - this.logger.warn(`[Git][getHEAD] Failed to parse HEAD file: ${err.message}`); + if (!this._isUsingRefTable) { + try { + // Attempt to parse the HEAD file + const result = await this.getHEADFS(); + + // Git 2.45 adds support for a new reference storage backend called "reftable", promising + // faster lookups, reads, and writes for repositories with any number of references. For + // backwards compatibility the `.git/HEAD` file contains `ref: refs/heads/.invalid`. More + // details are available at https://git-scm.com/docs/reftable + if (result.name === '.invalid') { + this._isUsingRefTable = true; + this.logger.warn(`[Git][getHEAD] Failed to parse HEAD file: Repository is using reftable format.`); + } else { + return result; + } + } + catch (err) { + this.logger.warn(`[Git][getHEAD] Failed to parse HEAD file: ${err.message}`); + } } try { diff --git a/extensions/git/src/historyProvider.ts b/extensions/git/src/historyProvider.ts index d4b1d0a39d5..d19311b302f 100644 --- a/extensions/git/src/historyProvider.ts +++ b/extensions/git/src/historyProvider.ts @@ -6,11 +6,10 @@ import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, SourceControlHistoryItem, SourceControlHistoryItemChange, SourceControlHistoryItemGroup, SourceControlHistoryOptions, SourceControlHistoryProvider, ThemeIcon, Uri, window, LogOutputChannel, SourceControlHistoryItemLabel } from 'vscode'; import { Repository, Resource } from './repository'; -import { IDisposable, dispose, filterEvent } from './util'; +import { IDisposable, dispose } from './util'; import { toGitUri } from './uri'; -import { Branch, RefType, UpstreamRef } from './api/git'; +import { Branch, LogOptions, RefType, UpstreamRef } from './api/git'; import { emojify, ensureEmojis } from './emoji'; -import { Operation } from './operation'; import { Commit } from './git'; export class GitHistoryProvider implements SourceControlHistoryProvider, FileDecorationProvider, IDisposable { @@ -43,12 +42,10 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec constructor(protected readonly repository: Repository, private readonly logger: LogOutputChannel) { this.disposables.push(repository.onDidRunGitStatus(() => this.onDidRunGitStatus(), this)); - this.disposables.push(filterEvent(repository.onDidRunOperation, e => e.operation === Operation.Refresh)(() => this.onDidRunGitStatus(true), this)); - this.disposables.push(window.registerFileDecorationProvider(this)); } - private async onDidRunGitStatus(force = false): Promise { + private async onDidRunGitStatus(): Promise { this.logger.trace('[GitHistoryProvider][onDidRunGitStatus] HEAD:', JSON.stringify(this._HEAD)); this.logger.trace('[GitHistoryProvider][onDidRunGitStatus] repository.HEAD:', JSON.stringify(this.repository.HEAD)); @@ -56,8 +53,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec const mergeBase = await this.resolveHEADMergeBase(); // Check if HEAD has changed - if (!force && - this._HEAD?.name === this.repository.HEAD?.name && + if (this._HEAD?.name === this.repository.HEAD?.name && this._HEAD?.commit === this.repository.HEAD?.commit && this._HEAD?.upstream?.name === this.repository.HEAD?.upstream?.name && this._HEAD?.upstream?.remote === this.repository.HEAD?.upstream?.remote && @@ -98,7 +94,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec } : undefined }; - this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemGroup(${force}): ${JSON.stringify(this.currentHistoryItemGroup)}`); + this.logger.trace(`[GitHistoryProvider][onDidRunGitStatus] currentHistoryItemGroup: ${JSON.stringify(this.currentHistoryItemGroup)}`); } async provideHistoryItems(historyItemGroupId: string, options: SourceControlHistoryOptions): Promise { @@ -137,22 +133,31 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec } async provideHistoryItems2(options: SourceControlHistoryOptions): Promise { - if (!this.currentHistoryItemGroup || !options.historyItemGroupIds || typeof options.limit === 'number' || !options.limit?.id) { + if (!this.currentHistoryItemGroup || !options.historyItemGroupIds) { return []; } // Deduplicate refNames const refNames = Array.from(new Set(options.historyItemGroupIds)); + let logOptions: LogOptions = { refNames, shortStats: true }; + try { - // Get the common ancestor commit, and commits - const [mergeBaseCommit, commits] = await Promise.all([ - this.repository.getCommit(options.limit.id), - this.repository.log({ range: `${options.limit.id}..`, refNames, shortStats: true }) - ]); + if (options.limit === undefined || typeof options.limit === 'number') { + logOptions = { ...logOptions, maxEntries: options.limit ?? 50 }; + } else if (typeof options.limit.id === 'string') { + // Get the common ancestor commit, and commits + const commit = await this.repository.getCommit(options.limit.id); + const commitParentId = commit.parents.length > 0 ? commit.parents[0] : await this.repository.getEmptyTree(); + + logOptions = { ...logOptions, range: `${commitParentId}..` }; + } - // Add common ancestor commit - commits.push(mergeBaseCommit); + if (typeof options.skip === 'number') { + logOptions = { ...logOptions, skip: options.skip }; + } + + const commits = await this.repository.log({ ...logOptions, silent: true }); await ensureEmojis(); @@ -160,7 +165,7 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec const newLineIndex = commit.message.indexOf('\n'); const subject = newLineIndex !== -1 ? commit.message.substring(0, newLineIndex) : commit.message; - const labels = this.resolveHistoryItemLabels(commit, refNames); + const labels = this.resolveHistoryItemLabels(commit); return { id: commit.hash, @@ -174,30 +179,24 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec }; }); } catch (err) { - this.logger.error(`[GitHistoryProvider][provideHistoryItems2] Failed to get history items '${options.limit.id}..': ${err}`); + this.logger.error(`[GitHistoryProvider][provideHistoryItems2] Failed to get history items with options '${JSON.stringify(options)}': ${err}`); return []; } } async provideHistoryItemSummary(historyItemId: string, historyItemParentId: string | undefined): Promise { - if (!historyItemParentId) { - const commit = await this.repository.getCommit(historyItemId); - historyItemParentId = commit.parents.length > 0 ? commit.parents[0] : `${historyItemId}^`; - } - + historyItemParentId = historyItemParentId ?? await this.repository.getEmptyTree(); const allChanges = await this.repository.diffBetweenShortStat(historyItemParentId, historyItemId); + return { id: historyItemId, parentIds: [historyItemParentId], message: '', statistics: allChanges }; } async provideHistoryItemChanges(historyItemId: string, historyItemParentId: string | undefined): Promise { - if (!historyItemParentId) { - const commit = await this.repository.getCommit(historyItemId); - historyItemParentId = commit.parents.length > 0 ? commit.parents[0] : `${historyItemId}^`; - } + historyItemParentId = historyItemParentId ?? await this.repository.getEmptyTree(); const historyItemChangesUri: Uri[] = []; const historyItemChanges: SourceControlHistoryItemChange[] = []; - const changes = await this.repository.diffBetween(historyItemParentId, historyItemId); + const changes = await this.repository.diffTrees(historyItemParentId, historyItemId); for (const change of changes) { const historyItemUri = change.uri.with({ @@ -293,14 +292,10 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec return this.historyItemDecorations.get(uri.toString()); } - private resolveHistoryItemLabels(commit: Commit, refNames: string[]): SourceControlHistoryItemLabel[] { + private resolveHistoryItemLabels(commit: Commit): SourceControlHistoryItemLabel[] { const labels: SourceControlHistoryItemLabel[] = []; for (const label of commit.refNames) { - if (!label.startsWith('HEAD -> ') && !refNames.includes(label)) { - continue; - } - for (const [key, value] of this.historyItemLabels) { if (label.startsWith(key)) { labels.push({ diff --git a/extensions/git/src/operation.ts b/extensions/git/src/operation.ts index 13370d59bf7..d960cedfdbb 100644 --- a/extensions/git/src/operation.ts +++ b/extensions/git/src/operation.ts @@ -158,7 +158,7 @@ export const Operation = { GetRemoteRefs: { kind: OperationKind.GetRemoteRefs, blocking: false, readOnly: true, remote: true, retry: false, showProgress: false } as GetRemoteRefsOperation, HashObject: { kind: OperationKind.HashObject, blocking: false, readOnly: false, remote: false, retry: false, showProgress: true } as HashObjectOperation, Ignore: { kind: OperationKind.Ignore, blocking: false, readOnly: false, remote: false, retry: false, showProgress: true } as IgnoreOperation, - Log: { kind: OperationKind.Log, blocking: false, readOnly: true, remote: false, retry: false, showProgress: true } as LogOperation, + Log: (showProgress: boolean) => ({ kind: OperationKind.Log, blocking: false, readOnly: true, remote: false, retry: false, showProgress }) as LogOperation, LogFile: { kind: OperationKind.LogFile, blocking: false, readOnly: true, remote: false, retry: false, showProgress: false } as LogFileOperation, Merge: { kind: OperationKind.Merge, blocking: false, readOnly: false, remote: false, retry: false, showProgress: true } as MergeOperation, MergeAbort: { kind: OperationKind.MergeAbort, blocking: false, readOnly: false, remote: false, retry: false, showProgress: true } as MergeAbortOperation, diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 5c14345e61a..8ba56b1a1ed 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -718,6 +718,8 @@ export class Repository implements Disposable { private _untrackedGroup: SourceControlResourceGroup; get untrackedGroup(): GitResourceGroup { return this._untrackedGroup as GitResourceGroup; } + private _EMPTY_TREE: string | undefined; + private _HEAD: Branch | undefined; get HEAD(): Branch | undefined { return this._HEAD; @@ -1046,8 +1048,9 @@ export class Repository implements Disposable { return this.run(Operation.Config(false), () => this.repository.config('local', key, value)); } - log(options?: LogOptions): Promise { - return this.run(Operation.Log, () => this.repository.log(options)); + log(options?: LogOptions & { silent?: boolean }): Promise { + const showProgress = !options || options.silent !== true; + return this.run(Operation.Log(showProgress), () => this.repository.log(options)); } logFile(uri: Uri, options?: LogFileOptions): Promise { @@ -1112,6 +1115,10 @@ export class Repository implements Disposable { return this.run(Operation.Diff, () => this.repository.diffBetweenShortStat(ref1, ref2)); } + diffTrees(treeish1: string, treeish2?: string): Promise { + return this.run(Operation.Diff, () => this.repository.diffTrees(treeish1, treeish2)); + } + getMergeBase(ref1: string, ref2: string, ...refs: string[]): Promise { return this.run(Operation.MergeBase, () => this.repository.getMergeBase(ref1, ref2, ...refs)); } @@ -1602,6 +1609,15 @@ export class Repository implements Disposable { return await this.repository.getCommit(ref); } + async getEmptyTree(): Promise { + if (!this._EMPTY_TREE) { + const result = await this.repository.exec(['hash-object', '-t', 'tree', '/dev/null']); + this._EMPTY_TREE = result.stdout.trim(); + } + + return this._EMPTY_TREE; + } + async getCommitCount(range: string): Promise<{ ahead: number; behind: number }> { return await this.run(Operation.RevList, () => this.repository.getCommitCount(range)); } @@ -1819,7 +1835,7 @@ export class Repository implements Disposable { return true; } - const maybeRebased = await this.run(Operation.Log, async () => { + const maybeRebased = await this.run(Operation.Log(true), async () => { try { const result = await this.repository.exec(['log', '--oneline', '--cherry', `${currentBranch ?? ''}...${currentBranch ?? ''}@{upstream}`, '--']); if (result.exitCode) { @@ -1943,7 +1959,8 @@ export class Repository implements Disposable { return await this.run(Operation.Ignore, async () => { const ignoreFile = `${this.repository.root}${path.sep}.gitignore`; const textToAppend = files - .map(uri => relativePath(this.repository.root, uri.fsPath).replace(/\\/g, '/')) + .map(uri => relativePath(this.repository.root, uri.fsPath) + .replace(/\\|\[/g, match => match === '\\' ? '/' : `\\${match}`)) .join('\n'); const document = await new Promise(c => fs.exists(ignoreFile, c)) diff --git a/extensions/git/src/terminal.ts b/extensions/git/src/terminal.ts index 867fddced84..05a4366d0c8 100644 --- a/extensions/git/src/terminal.ts +++ b/extensions/git/src/terminal.ts @@ -54,8 +54,8 @@ export class TerminalEnvironmentManager { export class TerminalShellExecutionManager { private readonly subcommands = new Set([ - 'add', 'branch', 'checkout', 'clean', 'commit', - 'fetch', 'reset', 'revert', 'pull', 'push', 'switch']); + 'add', 'branch', 'checkout', 'cherry-pick', 'clean', 'commit', 'fetch', 'merge', + 'mv', 'rebase', 'reset', 'restore', 'revert', 'rm', 'pull', 'push', 'stash', 'switch']); private readonly disposables: IDisposable[] = []; diff --git a/extensions/git/tsconfig.json b/extensions/git/tsconfig.json index 54d58aac432..75fb8217df7 100644 --- a/extensions/git/tsconfig.json +++ b/extensions/git/tsconfig.json @@ -20,7 +20,6 @@ "../../src/vscode-dts/vscode.proposed.scmTextDocument.d.ts", "../../src/vscode-dts/vscode.proposed.tabInputMultiDiff.d.ts", "../../src/vscode-dts/vscode.proposed.tabInputTextMerge.d.ts", - "../../src/vscode-dts/vscode.proposed.terminalShellIntegration.d.ts", "../../src/vscode-dts/vscode.proposed.timeline.d.ts", "../../src/vscode-dts/vscode.proposed.quickInputButtonLocation.d.ts", "../types/lib.textEncoder.d.ts" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 3306b4b9042..7fcbc7f151c 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -13,9 +13,6 @@ "Other" ], "api": "none", - "enabledApiProposals": [ - "authGetSessions" - ], "extensionKind": [ "ui", "workspace" diff --git a/extensions/github-authentication/src/github.ts b/extensions/github-authentication/src/github.ts index 39557dc8e26..ed584c65f8b 100644 --- a/extensions/github-authentication/src/github.ts +++ b/extensions/github-authentication/src/github.ts @@ -11,7 +11,7 @@ import { PromiseAdapter, arrayEquals, promiseFromEvent } from './common/utils'; import { ExperimentationTelemetry } from './common/experimentationService'; import { Log } from './common/logger'; import { crypto } from './node/crypto'; -import { CANCELLATION_ERROR, TIMED_OUT_ERROR, USER_CANCELLATION_ERROR } from './common/errors'; +import { TIMED_OUT_ERROR, USER_CANCELLATION_ERROR } from './common/errors'; interface SessionData { id: string; @@ -316,39 +316,13 @@ export class GitHubAuthenticationProvider implements vscode.AuthenticationProvid const sessions = await this._sessionsPromise; - const forcedLogin = options?.account?.label; - const backupLogin = sessions[0]?.account.label; - this._logger.info(`Logging in with '${forcedLogin ? forcedLogin : 'any'}' account...`); + // First we use the account specified in the options, otherwise we use the first account we have to seed auth. + const loginWith = options?.account?.label ?? sessions[0]?.account.label; + this._logger.info(`Logging in with '${loginWith ? loginWith : 'any'}' account...`); const scopeString = sortedScopes.join(' '); - const token = await this._githubServer.login(scopeString, forcedLogin ?? backupLogin); + const token = await this._githubServer.login(scopeString, loginWith); const session = await this.tokenToSession(token, scopes); - - // If an account was specified, we should ensure that the token we got back is for that account. - if (forcedLogin) { - if (session.account.label !== forcedLogin) { - const keepNewAccount = vscode.l10n.t('Keep {0}', session.account.label); - const tryAgain = vscode.l10n.t('Login with {0}', forcedLogin); - const result = await vscode.window.showWarningMessage( - vscode.l10n.t('Incorrect account detected'), - { modal: true, detail: vscode.l10n.t('The chosen account, {0}, does not match the requested account, {1}.', session.account.label, forcedLogin) }, - keepNewAccount, - tryAgain - ); - if (result === tryAgain) { - return await this.createSession(scopes, { - ...options, - // The id doesn't matter here, we just need to pass the label through - account: { id: forcedLogin, label: forcedLogin } - }); - } - // Cancelled result - if (!result) { - throw new Error(CANCELLATION_ERROR); - } - // Keep result continues on - } - } this.afterSessionLoad(session); const sessionIndex = sessions.findIndex( diff --git a/extensions/github-authentication/tsconfig.json b/extensions/github-authentication/tsconfig.json index 70eba984a26..5e4713e9f3b 100644 --- a/extensions/github-authentication/tsconfig.json +++ b/extensions/github-authentication/tsconfig.json @@ -12,7 +12,6 @@ }, "include": [ "src/**/*", - "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.authGetSessions.d.ts" + "../../src/vscode-dts/vscode.d.ts" ] } diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index ac026b973eb..913826409aa 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -259,7 +259,7 @@ }, "dependencies": { "@vscode/extension-telemetry": "^0.9.0", - "vscode-languageclient": "^10.0.0-next.8", + "vscode-languageclient": "10.0.0-next.8", "vscode-uri": "^3.0.8" }, "devDependencies": { diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index c1ddc242fa4..3698bf8f9a3 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -10,10 +10,10 @@ "main": "./out/node/htmlServerMain", "dependencies": { "@vscode/l10n": "^0.0.18", - "vscode-css-languageservice": "^6.3.0", - "vscode-html-languageservice": "^5.3.0", - "vscode-languageserver": "^10.0.0-next.6", - "vscode-languageserver-textdocument": "^1.0.11", + "vscode-css-languageservice": "^6.3.1", + "vscode-html-languageservice": "^5.3.1", + "vscode-languageserver": "10.0.0-next.6", + "vscode-languageserver-textdocument": "^1.0.12", "vscode-uri": "^3.0.8" }, "devDependencies": { diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index caaf929d895..1d915ccf107 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -24,23 +24,23 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -vscode-css-languageservice@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.3.0.tgz#51724d193d19b1a9075b1cef5cfeea6a555d2aa4" - integrity sha512-nU92imtkgzpCL0xikrIb8WvedV553F2BENzgz23wFuok/HLN5BeQmroMy26pUwFxV2eV8oNRmYCUv8iO7kSMhw== +vscode-css-languageservice@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-6.3.1.tgz#56733c90686db56855ccc156a534a68b8c1f2187" + integrity sha512-1BzTBuJfwMc3A0uX4JBdJgoxp74cjj4q2mDJdp49yD/GuAq4X0k5WtK6fNcMYr+FfJ9nqgR6lpfCSZDkARJ5qQ== dependencies: "@vscode/l10n" "^0.0.18" - vscode-languageserver-textdocument "^1.0.11" + vscode-languageserver-textdocument "^1.0.12" vscode-languageserver-types "3.17.5" vscode-uri "^3.0.8" -vscode-html-languageservice@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-5.3.0.tgz#298ae5600c6749cbb95838975d07f449c44cb478" - integrity sha512-C4Z3KsP5Ih+fjHpiBc5jxmvCl+4iEwvXegIrzu2F5pktbWvQaBT3YkVPk8N+QlSSMk8oCG6PKtZ/Sq2YHb5e8g== +vscode-html-languageservice@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-5.3.1.tgz#93cac1cebb42165b52a15220f02c47d1320fc43a" + integrity sha512-ysUh4hFeW/WOWz/TO9gm08xigiSsV/FOAZ+DolgJfeLftna54YdmZ4A+lIn46RbdO3/Qv5QHTn1ZGqmrXQhZyA== dependencies: "@vscode/l10n" "^0.0.18" - vscode-languageserver-textdocument "^1.0.11" + vscode-languageserver-textdocument "^1.0.12" vscode-languageserver-types "^3.17.5" vscode-uri "^3.0.8" @@ -57,10 +57,10 @@ vscode-languageserver-protocol@3.17.6-next.6: vscode-jsonrpc "9.0.0-next.4" vscode-languageserver-types "3.17.6-next.4" -vscode-languageserver-textdocument@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" - integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== +vscode-languageserver-textdocument@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== vscode-languageserver-types@3.17.5, vscode-languageserver-types@^3.17.5: version "3.17.5" @@ -72,7 +72,7 @@ vscode-languageserver-types@3.17.6-next.4: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.6-next.4.tgz#6670939eb98f00aa7b05021dc3dd7fe9aa4453ea" integrity sha512-SeJTpH/S14EbxOAVaOUoGVqPToqpRTld5QO5Ghig3AlbFJTFF9Wu7srHMfa85L0SX1RYAuuCSFKJVVCxDIk1/Q== -vscode-languageserver@^10.0.0-next.6: +vscode-languageserver@10.0.0-next.6: version "10.0.0-next.6" resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-10.0.0-next.6.tgz#0db118a93fe010c6b40cd04e91a15d09e7b60b60" integrity sha512-0Lh1nhQfSxo5Ob+ayYO1QTIsDix2/Lc72Urm1KZrCFxK5zIFYaEh3QFeM9oZih4Rzs0ZkQPXXnoHtpvs5GT+Zw== diff --git a/extensions/html-language-features/yarn.lock b/extensions/html-language-features/yarn.lock index aa2ea1c6840..46688b667d8 100644 --- a/extensions/html-language-features/yarn.lock +++ b/extensions/html-language-features/yarn.lock @@ -154,7 +154,7 @@ vscode-jsonrpc@9.0.0-next.4: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0-next.4.tgz#ba403ddb3b82ca578179963dbe08e120a935f50d" integrity sha512-zSVIr58lJSMYKIsZ5P7GtBbv1eEx25eNyOf0NmEzxmn1GhUNJAVAb5hkA1poKUwj1FRMwN6CeyWxZypmr8SsQQ== -vscode-languageclient@^10.0.0-next.8: +vscode-languageclient@10.0.0-next.8: version "10.0.0-next.8" resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-10.0.0-next.8.tgz#5afa0ced3b2ac68d31cc1c48edc4f289744542a0" integrity sha512-D9inIHgqKayO9Tv0MeLb3XIL76yTuWmKdHqcGZKzjtQrMGJgASJDYWTapu+yAjEpDp0gmVOaCYyIlLB86ncDoQ== diff --git a/extensions/ipynb/src/serializers.ts b/extensions/ipynb/src/serializers.ts index 3eb6e90eabd..eedad802742 100644 --- a/extensions/ipynb/src/serializers.ts +++ b/extensions/ipynb/src/serializers.ts @@ -123,7 +123,10 @@ function createCodeCellFromNotebookCell(cell: NotebookCellData, preferredLanguag const codeCell: any = { cell_type: 'code', - execution_count: cell.executionSummary?.executionOrder ?? null, + // Possible the metadata was edited as part of diff view + // In diff view we display execution_count as part of metadata, hence when execution count changes in metadata, + // We need to change that here as well, i.e. give preference to any execution_count value in metadata. + execution_count: cellMetadata.execution_count ?? cell.executionSummary?.executionOrder ?? null, source: splitMultilineString(cell.value.replace(/\r\n/g, '\n')), outputs: (cell.outputs || []).map(translateCellDisplayOutput), metadata: cellMetadata.metadata diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index fa8004e2b02..dc9d4a272eb 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -162,8 +162,8 @@ }, "dependencies": { "@vscode/extension-telemetry": "^0.9.0", - "request-light": "^0.7.0", - "vscode-languageclient": "^10.0.0-next.8" + "request-light": "^0.8.0", + "vscode-languageclient": "10.0.0-next.8" }, "devDependencies": { "@types/node": "20.x" diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 8472ca618a4..1ac5eb9159d 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -13,10 +13,10 @@ "main": "./out/node/jsonServerMain", "dependencies": { "@vscode/l10n": "^0.0.18", - "jsonc-parser": "^3.2.1", - "request-light": "^0.7.0", - "vscode-json-languageservice": "^5.4.0", - "vscode-languageserver": "^10.0.0-next.6", + "jsonc-parser": "^3.3.1", + "request-light": "^0.8.0", + "vscode-json-languageservice": "^5.4.1", + "vscode-languageserver": "10.0.0-next.6", "vscode-uri": "^3.0.8" }, "devDependencies": { diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 608619637e4..4c7fd8191a7 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -19,34 +19,29 @@ resolved "https://registry.yarnpkg.com/@vscode/l10n/-/l10n-0.0.18.tgz#916d3a5e960dbab47c1c56f58a7cb5087b135c95" integrity sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ== -jsonc-parser@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== +jsonc-parser@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" + integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ== -jsonc-parser@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.0.tgz#030d182672c8ffc2805db95467c83ffc0b033d9d" - integrity sha512-RK1Xb5alM78sdXpB2hqqK7jxAE5jTRH05GvUiLWqh7Vbp6OPHuJYlsAMRUDYNYJTAQgkmhHgkdwOEknxwP4ojQ== - -request-light@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.7.0.tgz#885628bb2f8040c26401ebf258ec51c4ae98ac2a" - integrity sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q== +request-light@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.8.0.tgz#6ec01e4b526638358c2c6353efa1c6aaf057dfa0" + integrity sha512-bH6E4PMmsEXYrLX6Kr1vu+xI3HproB1vECAwaPSJeroLE1kpWE3HR27uB4icx+6YORu1ajqBJXxuedv8ZQg5Lw== undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -vscode-json-languageservice@^5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.4.0.tgz#caf1aabc81b1df9faf6a97e4c34e13a2d10a8cdf" - integrity sha512-NCkkCr63OHVkE4lcb0xlUAaix6vE5gHQW4NrswbLEh3ArXj81lrGuFTsGEYEUXlNHdnc53vWPcjeSy/nMTrfXg== +vscode-json-languageservice@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-5.4.1.tgz#dc9d3b96c714d8d4feb58a219747b1239d6dd5e6" + integrity sha512-5czFGNyVPxz3ZJYl8R3a3SuIj5gjhmGF4Wv05MRPvD4DEnHK6b8km4VbNMJNHBlTCh7A0aHzUbPVzo+0C18mCA== dependencies: "@vscode/l10n" "^0.0.18" - jsonc-parser "^3.3.0" - vscode-languageserver-textdocument "^1.0.11" + jsonc-parser "^3.3.1" + vscode-languageserver-textdocument "^1.0.12" vscode-languageserver-types "^3.17.5" vscode-uri "^3.0.8" @@ -63,10 +58,10 @@ vscode-languageserver-protocol@3.17.6-next.6: vscode-jsonrpc "9.0.0-next.4" vscode-languageserver-types "3.17.6-next.4" -vscode-languageserver-textdocument@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz#0822a000e7d4dc083312580d7575fe9e3ba2e2bf" - integrity sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA== +vscode-languageserver-textdocument@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz#457ee04271ab38998a093c68c2342f53f6e4a631" + integrity sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA== vscode-languageserver-types@3.17.6-next.4: version "3.17.6-next.4" @@ -78,7 +73,7 @@ vscode-languageserver-types@^3.17.5: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz#3273676f0cf2eab40b3f44d085acbb7f08a39d8a" integrity sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg== -vscode-languageserver@^10.0.0-next.6: +vscode-languageserver@10.0.0-next.6: version "10.0.0-next.6" resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-10.0.0-next.6.tgz#0db118a93fe010c6b40cd04e91a15d09e7b60b60" integrity sha512-0Lh1nhQfSxo5Ob+ayYO1QTIsDix2/Lc72Urm1KZrCFxK5zIFYaEh3QFeM9oZih4Rzs0ZkQPXXnoHtpvs5GT+Zw== diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index c825de07683..82a6ebb8e49 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -137,10 +137,10 @@ minimatch@^9.0.3: dependencies: brace-expansion "^2.0.1" -request-light@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.7.0.tgz#885628bb2f8040c26401ebf258ec51c4ae98ac2a" - integrity sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q== +request-light@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.8.0.tgz#6ec01e4b526638358c2c6353efa1c6aaf057dfa0" + integrity sha512-bH6E4PMmsEXYrLX6Kr1vu+xI3HproB1vECAwaPSJeroLE1kpWE3HR27uB4icx+6YORu1ajqBJXxuedv8ZQg5Lw== semver@^7.6.0: version "7.6.0" @@ -159,7 +159,7 @@ vscode-jsonrpc@9.0.0-next.4: resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0-next.4.tgz#ba403ddb3b82ca578179963dbe08e120a935f50d" integrity sha512-zSVIr58lJSMYKIsZ5P7GtBbv1eEx25eNyOf0NmEzxmn1GhUNJAVAb5hkA1poKUwj1FRMwN6CeyWxZypmr8SsQQ== -vscode-languageclient@^10.0.0-next.8: +vscode-languageclient@10.0.0-next.8: version "10.0.0-next.8" resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-10.0.0-next.8.tgz#5afa0ced3b2ac68d31cc1c48edc4f289744542a0" integrity sha512-D9inIHgqKayO9Tv0MeLb3XIL76yTuWmKdHqcGZKzjtQrMGJgASJDYWTapu+yAjEpDp0gmVOaCYyIlLB86ncDoQ== diff --git a/extensions/julia/cgmanifest.json b/extensions/julia/cgmanifest.json index 9daaee1fdd8..b5d8a03be09 100644 --- a/extensions/julia/cgmanifest.json +++ b/extensions/julia/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "JuliaEditorSupport/atom-language-julia", "repositoryUrl": "https://github.com/JuliaEditorSupport/atom-language-julia", - "commitHash": "663bf8d943fd8440f4ae7565f73327dd616bf191" + "commitHash": "c686684f18153687886e7d19c1bfc3a33076b1ab" } }, "license": "MIT", - "version": "0.22.1" + "version": "0.23.0" } ], "version": 1 diff --git a/extensions/julia/syntaxes/julia.tmLanguage.json b/extensions/julia/syntaxes/julia.tmLanguage.json index 35a4ea7d927..f66fda97f70 100644 --- a/extensions/julia/syntaxes/julia.tmLanguage.json +++ b/extensions/julia/syntaxes/julia.tmLanguage.json @@ -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/JuliaEditorSupport/atom-language-julia/commit/663bf8d943fd8440f4ae7565f73327dd616bf191", + "version": "https://github.com/JuliaEditorSupport/atom-language-julia/commit/c686684f18153687886e7d19c1bfc3a33076b1ab", "name": "Julia", "scopeName": "source.julia", "comment": "This grammar is used by Atom (Oniguruma), GitHub (PCRE), and VSCode (Oniguruma),\nso all regexps must be compatible with both engines.\n\nSpecs:\n- https://github.com/kkos/oniguruma/blob/master/doc/RE\n- https://www.pcre.org/current/doc/html/", @@ -333,7 +333,7 @@ "name": "keyword.control.using.julia" }, { - "match": "(?<=\\w\\s)\\b(as)\\b(?=\\s\\w)", + "match": "(?<=\\S\\s+)\\b(as)\\b(?=\\s+\\S)", "name": "keyword.control.as.julia" }, { diff --git a/extensions/latex/cgmanifest.json b/extensions/latex/cgmanifest.json index b537c48ee8c..3c7203d5d2a 100644 --- a/extensions/latex/cgmanifest.json +++ b/extensions/latex/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "jlelong/vscode-latex-basics", "repositoryUrl": "https://github.com/jlelong/vscode-latex-basics", - "commitHash": "5d7c2a4e451a932b776f6d9342087be6a1e8c0a1" + "commitHash": "969429cb9230a63f9155987f069acd4234d10e1a" } }, "license": "MIT", diff --git a/extensions/latex/syntaxes/LaTeX.tmLanguage.json b/extensions/latex/syntaxes/LaTeX.tmLanguage.json index 76486732195..bc97a73bda8 100644 --- a/extensions/latex/syntaxes/LaTeX.tmLanguage.json +++ b/extensions/latex/syntaxes/LaTeX.tmLanguage.json @@ -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/jlelong/vscode-latex-basics/commit/9cd6bc151f4b9df5d9aeb1e39e30071018d3cb2a", + "version": "https://github.com/jlelong/vscode-latex-basics/commit/969429cb9230a63f9155987f069acd4234d10e1a", "name": "LaTeX", "scopeName": "text.tex.latex", "patterns": [ @@ -94,7 +94,7 @@ "4": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -1900,7 +1900,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -1910,7 +1910,7 @@ "5": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2368,7 +2368,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2404,7 +2404,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2562,7 +2562,7 @@ "name": "meta.scope.item.latex" }, { - "begin": "((\\\\)(?:[aA]uto|foot|full|no|ref|short|[tT]ext|[pP]aren|[sS]mart)?[cC]ite(?:al)?(?:p|s|t|author|year(?:par)?|title)?[ANP]*\\*?)((?:(?:\\([^\\)]*\\)){0,2}(?:\\[[^\\]]*\\]){0,2}\\{[\\p{Alphabetic}:.]*\\})*)(?:([<\\[])[^\\]<>]*([>\\]]))?(?:(\\[)[^\\]]*(\\]))?(\\{)", + "begin": "((\\\\)(?:[aA]uto|foot|full|no|ref|short|[tT]ext|[pP]aren|[sS]mart)?[cC]ite(?:al)?(?:p|s|t|author|year(?:par)?|title)?[ANP]*\\*?)((?:(?:\\([^\\)]*\\)){0,2}(?:\\[[^\\]]*\\]){0,2}\\{[\\p{Alphabetic}\\p{Number}_:.-]*\\})*)(<[^\\]<>]*>)?((?:\\[[^\\]]*\\])*)(\\{)", "captures": { "1": { "name": "keyword.control.cite.latex" @@ -2578,18 +2578,20 @@ ] }, "4": { - "name": "punctuation.definition.arguments.optional.begin.latex" + "patterns": [ + { + "include": "#optional-arg-angle-no-highlight" + } + ] }, "5": { - "name": "punctuation.definition.arguments.optional.end.latex" + "patterns": [ + { + "include": "#optional-arg-bracket-no-highlight" + } + ] }, "6": { - "name": "punctuation.definition.arguments.optional.begin.latex" - }, - "7": { - "name": "punctuation.definition.arguments.optional.end.latex" - }, - "8": { "name": "punctuation.definition.arguments.begin.latex" } }, @@ -2602,6 +2604,7 @@ "name": "meta.citation.latex", "patterns": [ { + "match": "((%).*)$", "captures": { "1": { "name": "comment.line.percentage.tex" @@ -2609,8 +2612,7 @@ "2": { "name": "punctuation.definition.comment.tex" } - }, - "match": "((%).*)$" + } }, { "match": "[\\p{Alphabetic}\\p{Number}:.-]+", @@ -2740,7 +2742,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2783,7 +2785,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2820,7 +2822,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -2867,7 +2869,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -3048,7 +3050,7 @@ "name": "punctuation.definition.variable.latex" } }, - "match": "(\\\\)[cgl](?:[_\\p{Alphabetic}@]+)+_[a-z]+", + "match": "(\\\\)(?:[cgl]_+[_\\p{Alphabetic}@]+_[a-z]+|[qs]_[_\\p{Alphabetic}@]+[\\p{Alphabetic}@])", "name": "variable.other.latex3.latex" }, { @@ -3073,27 +3075,29 @@ { "captures": { "1": { - "name": "punctuation.definition.arguments.optional.begin.latex" + "patterns": [ + { + "include": "#optional-arg-parenthesis-no-highlight" + } + ] }, "2": { - "name": "punctuation.definition.arguments.optional.end.latex" + "patterns": [ + { + "include": "#optional-arg-bracket-no-highlight" + } + ] }, "3": { - "name": "punctuation.definition.arguments.optional.begin.latex" - }, - "4": { - "name": "punctuation.definition.arguments.optional.end.latex" - }, - "5": { "name": "punctuation.definition.arguments.begin.latex" }, - "6": { + "4": { "name": "constant.other.reference.citation.latex" }, - "7": { + "5": { "name": "punctuation.definition.arguments.end.latex" }, - "8": { + "6": { "patterns": [ { "include": "#autocites-arg" @@ -3101,7 +3105,7 @@ ] } }, - "match": "(?:(\\()[^\\)]*(\\))){0,2}(?:(\\[)[^\\]]*(\\])){0,2}(\\{)([\\p{Alphabetic}\\p{Number}:.]+)(\\})(.*)" + "match": "((?:\\([^\\)]*\\)){0,2})((?:\\[[^\\]]*\\]){0,2})(\\{)([\\p{Alphabetic}\\p{Number}_:.-]+)(\\})(.*)" } ] }, @@ -3159,7 +3163,7 @@ "3": { "patterns": [ { - "include": "#optional-arg" + "include": "#optional-arg-bracket" } ] }, @@ -3222,7 +3226,7 @@ } ] }, - "optional-arg": { + "optional-arg-bracket": { "patterns": [ { "captures": { @@ -3240,6 +3244,73 @@ "name": "meta.parameter.optional.latex" } ] + }, + "optional-arg-parenthesis": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.arguments.optional.begin.latex" + }, + "2": { + "name": "variable.parameter.function.latex" + }, + "3": { + "name": "punctuation.definition.arguments.optional.end.latex" + } + }, + "match": "(\\()([^\\(]*?)(\\))", + "name": "meta.parameter.optional.latex" + } + ] + }, + "optional-arg-bracket-no-highlight": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.arguments.optional.begin.latex" + }, + "2": { + "name": "punctuation.definition.arguments.optional.end.latex" + } + }, + "match": "(\\[)[^\\[]*?(\\])", + "name": "meta.parameter.optional.latex" + } + ] + }, + "optional-arg-angle-no-highlight": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.arguments.optional.begin.latex" + }, + "2": { + "name": "punctuation.definition.arguments.optional.end.latex" + } + }, + "match": "(<)[^<]*?(>)", + "name": "meta.parameter.optional.latex" + } + ] + }, + "optional-arg-parenthesis-no-highlight": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.definition.arguments.optional.begin.latex" + }, + "2": { + "name": "punctuation.definition.arguments.optional.end.latex" + } + }, + "match": "(\\()[^\\(]*?(\\))", + "name": "meta.parameter.optional.latex" + } + ] } } } \ No newline at end of file diff --git a/extensions/less/cgmanifest.json b/extensions/less/cgmanifest.json index a8d1702aa82..69a66b5d9b5 100644 --- a/extensions/less/cgmanifest.json +++ b/extensions/less/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "language-less", "repositoryUrl": "https://github.com/radium-v/Better-Less", - "commitHash": "b06a4555c711a6ef0d76cf2b4fc8b929a6ce551a" + "commitHash": "fb9c21917193746433743a7c971b70230b40bc2b" } }, "license": "MIT", diff --git a/extensions/less/syntaxes/less.tmLanguage.json b/extensions/less/syntaxes/less.tmLanguage.json index cea782810fb..6f57a48e02d 100644 --- a/extensions/less/syntaxes/less.tmLanguage.json +++ b/extensions/less/syntaxes/less.tmLanguage.json @@ -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/radium-v/Better-Less/commit/b06a4555c711a6ef0d76cf2b4fc8b929a6ce551a", + "version": "https://github.com/radium-v/Better-Less/commit/fb9c21917193746433743a7c971b70230b40bc2b", "name": "Less", "scopeName": "source.css.less", "patterns": [ @@ -40,6 +40,14 @@ "match": "(?i:[-+]?(?:(?:\\d*\\.\\d+(?:[eE](?:[-+]?\\d+))*)|(?:[-+]?\\d+))(deg|grad|rad|turn))\\b", "name": "constant.numeric.less" }, + "arbitrary-repetition": { + "captures": { + "1": { + "name": "punctuation.definition.arbitrary-repetition.less" + } + }, + "match": "\\s*(?:(,))" + }, "at-charset": { "begin": "\\s*((@)charset\\b)\\s*", "captures": { @@ -268,6 +276,9 @@ "patterns": [ { "include": "#keyframe-name" + }, + { + "include": "#arbitrary-repetition" } ] } @@ -700,6 +711,9 @@ }, { "include": "#less-math" + }, + { + "include": "#relative-color" } ] } @@ -718,6 +732,7 @@ "name": "support.function.color.less" } }, + "comment": "rgb(), rgba()", "end": "\\)", "endCaptures": { "0": { @@ -747,6 +762,9 @@ { "include": "#comma-delimiter" }, + { + "include": "#value-separator" + }, { "include": "#percentage-type" }, @@ -758,12 +776,13 @@ ] }, { - "begin": "\\b(hs(l|v)a?|hwb)(?=\\()", + "begin": "\\b(hsla|hsl|hwb|oklab|oklch|lab|lch)(?=\\()", "beginCaptures": { "1": { "name": "support.function.color.less" } }, + "comment": "hsla, hsl, hwb, oklab, oklch, lab, lch", "end": "\\)", "endCaptures": { "0": { @@ -781,6 +800,9 @@ }, "end": "(?=\\))", "patterns": [ + { + "include": "#color-values" + }, { "include": "#less-strings" }, @@ -801,6 +823,47 @@ }, { "include": "#number-type" + }, + { + "include": "#calc-function" + }, + { + "include": "#value-separator" + } + ] + } + ] + }, + { + "begin": "\\b(light-dark)(?=\\()", + "beginCaptures": { + "1": { + "name": "support.function.color.less" + } + }, + "comment": "light-dark()", + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.end.less" + } + }, + "name": "meta.function-call.less", + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.begin.less" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#color-values" + }, + { + "include": "#comma-delimiter" } ] } @@ -845,6 +908,9 @@ }, "match": "(#)(\\h{3}|\\h{4}|\\h{6}|\\h{8})\\b", "name": "constant.other.color.rgb-value.less" + }, + { + "include": "#relative-color" } ] }, @@ -1048,12 +1114,16 @@ ] }, "cubic-bezier-function": { - "begin": "\\b(cubic-bezier)(?=\\()", + "begin": "\\b(cubic-bezier)(\\()", "beginCaptures": { - "0": { + "1": { "name": "support.function.timing.less" + }, + "2": { + "name": "punctuation.definition.group.begin.less" } }, + "contentName": "meta.group.less", "end": "\\)", "endCaptures": { "0": { @@ -1063,24 +1133,22 @@ "name": "meta.function-call.less", "patterns": [ { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.group.begin.less" - } - }, - "end": "(?=\\))", - "patterns": [ - { - "include": "#var-function" - }, - { - "include": "#comma-delimiter" - }, - { - "include": "#number-type" - } - ] + "include": "#less-functions" + }, + { + "include": "#calc-function" + }, + { + "include": "#less-variables" + }, + { + "include": "#var-function" + }, + { + "include": "#comma-delimiter" + }, + { + "include": "#number-type" } ] }, @@ -1105,13 +1173,13 @@ "include": "#frequency-type" }, { - "include": "#length-type" + "include": "#time-type" }, { - "include": "#resolution-type" + "include": "#length-type" }, { - "include": "#time-type" + "include": "#resolution-type" } ] }, @@ -1611,6 +1679,15 @@ } ] }, + "important": { + "captures": { + "1": { + "name": "punctuation.separator.less" + } + }, + "match": "(\\!)\\s*important", + "name": "keyword.other.important.less" + }, "integer-type": { "match": "(?:[-+]?\\d+)", "name": "constant.numeric.less" @@ -1757,6 +1834,7 @@ "name": "support.function.color-definition.less" } }, + "comment": "argb()", "end": "\\)", "endCaptures": { "0": { @@ -1786,6 +1864,59 @@ ] } ] + }, + { + "begin": "\\b(hsva?)(?=\\()", + "beginCaptures": { + "1": { + "name": "support.function.color.less" + } + }, + "comment": "hsva(), hsv()", + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.end.less" + } + }, + "name": "meta.function-call.less", + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.begin.less" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#integer-type" + }, + { + "include": "#percentage-type" + }, + { + "include": "#number-type" + }, + { + "include": "#less-strings" + }, + { + "include": "#less-variables" + }, + { + "include": "#var-function" + }, + { + "include": "#calc-function" + }, + { + "include": "#comma-delimiter" + } + ] + } + ] } ] }, @@ -3515,7 +3646,48 @@ "name": "support.constant.property-value.less" }, { - "match": "(?x)\\b(\n absolute|active|add\n|all(-(petite|small)-caps|-scroll)?\n|alpha(betic)?\n|alternate(-reverse)?\n|always|annotation|antialiased|at\n|auto(hiding-scrollbar)?\n|avoid(-column|-page|-region)?\n|background(-color|-image|-position|-size)?\n|backwards|balance|baseline|below|bevel|bicubic|bidi-override|blink\n|block(-(line-height|start|end))?\n|blur\n|bold(er)?\n|border(-bottom|-left|-right|-top)?-(color|radius|width|style)\n|border-(bottom|top)-(left|right)-radius\n|border-image(-outset|-repeat|-slice|-source|-width)?\n|border(-bottom|-left|-right|-top|-collapse|-spacing|-box)?\n|both|bottom\n|box(-shadow)?\n|break-(all|word|spaces)\n|brightness\n|butt(on)?\n|capitalize\n|cent(er|ral)\n|char(acter-variant)?\n|cjk-ideographic|clip|clone|close-quote\n|closest-(corner|side)\n|col-resize|collapse\n|color(-stop|-burn|-dodge)?\n|column((-count|-gap|-reverse|-rule(-color|-width)?|-width)|s)?\n|common-ligatures|condensed|consider-shifts|contain\n|content(-box|s)?\n|contextual|contrast|cover\n|crisp(-e|E)dges\n|crop\n|cross(hair)?\n|da(rken|shed)\n|default|dense|diagonal-fractions|difference|disabled\n|discard|discretionary-ligatures|disregard-shifts\n|distribute(-all-lines|-letter|-space)?\n|dotted|double|drop-shadow\n|(nwse|nesw|ns|ew|sw|se|nw|ne|w|s|e|n)-resize\n|ease(-in-out|-in|-out)?\n|element|ellipsis|embed|end|EndColorStr|evenodd\n|exclu(de(-ruby)?|sion)\n|expanded\n|(extra|semi|ultra)-(condensed|expanded)\n|farthest-(corner|side)?\n|fill(-box|-opacity)?\n|filter\n|fit-content\n|fixed\n|flat\n|flex((-basis|-end|-grow|-shrink|-start)|box)?\n|flip|flood-color\n|font(-size(-adjust)?|-stretch|-weight)?\n|forwards\n|from(-image)?\n|full-width|gap|geometricPrecision|glyphs|gradient|grayscale\n|grid((-column|-row)?-gap|-height)?\n|groove|hand|hanging|hard-light|height|help|hidden|hide\n|historical-(forms|ligatures)\n|horizontal(-tb)?\n|hue\n|ideograph(-alpha|-numeric|-parenthesis|-space|ic)\n|inactive|include-ruby|infinite|inherit|initial\n|inline(-(block|box|flex(box)?|line-height|table|start|end))?\n|inset|inside\n|inter(-ideograph|-word|sect)\n|invert|isolat(e|ion)|italic\n|jis(04|78|83|90)\n|justify(-all)?\n|keep-all\n|large[r]?\n|last|layout|left|letter-spacing\n|light(e[nr]|ing-color)\n|line(-edge|-height|-through)?\n|linear(-gradient|RGB)?\n|lining-nums|list-item|local|loose|lowercase|lr-tb|ltr\n|lumin(osity|ance)|manual\n|manipulation\n|margin(-bottom|-box|-left|-right|-top)?\n|marker(-offset|s)?\n|match-parent\n|mathematical\n|max-(content|height|lines|size|width)\n|medium|middle\n|min-(content|height|width)\n|miter|mixed|move|multiply|newspaper\n|no-(change|clip|(close|open)-quote|(common|discretionary|historical)-ligatures|contextual|drop|repeat)\n|none|nonzero|normal|not-allowed|nowrap|oblique\n|offset(-after|-before|-end|-start)?\n|oldstyle-nums|opacity|open-quote\n|optimize(Legibility|Precision|Quality|Speed)\n|order|ordinal|ornaments\n|outline(-color|-offset|-width)?\n|outset|outside|over(line|-edge|lay)\n|padding(-bottom|-box|-left|-right|-top|-box)?\n|page|paint(ed)?|paused\n|pan-(x|left|right|y|up|down)\n|perspective-origin\n|petite-caps|pixelated|pointer\n|pinch-zoom\n|pretty\n|pre(-line|-wrap)?\n|preserve(-3d|-breaks|-spaces)?\n|progid:DXImageTransform.Microsoft.(Alpha|Blur|dropshadow|gradient|Shadow)\n|progress\n|proportional-(nums|width)\n|radial-gradient|recto|region|relative\n|repeat(-[xy])?\n|repeating-(linear|radial)-gradient\n|replaced|reset-size|reverse|revert(-layer)?|ridge|right\n|round\n|row(-gap|-resize|-reverse)?\n|rtl|ruby|running|saturat(e|ion)|screen\n|scroll(-position|bar)?\n|separate|sepia\n|scale-down\n|shape-(image-threshold|margin|outside)\n|show\n|sideways(-lr|-rl)?\n|simplified\n|size\n|slashed-zero|slice\n|small(-caps|er)?\n|smooth|snap|solid|soft-light\n|space(-around|-between)?\n|span|sRGB\n|stable\n|stack(ed-fractions)?\n|start(ColorStr)?\n|static\n|step-(end|start)\n|sticky\n|stop-(color|opacity)\n|stretch|strict\n|stroke(-box|-dash(array|offset)|-miterlimit|-opacity|-width)?\n|style(set)?\n|stylistic\n|sub(grid|pixel-antialiased|tract)?\n|super|swash\n|table(-caption|-cell|(-column|-footer|-header|-row)-group|-column|-row)?\n|tabular-nums|tb-rl\n|text((-bottom|-(decoration|emphasis)-color|-indent|-(over|under)-edge|-shadow|-size(-adjust)?|-top)|field)?\n|thi(ck|n)\n|titling-ca(ps|se)\n|to[p]?\n|touch|traditional\n|transform(-origin)?\n|under(-edge|line)?\n|unicase|unset|uppercase|upright\n|use-(glyph-orientation|script)\n|verso\n|vertical(-align|-ideographic|-lr|-rl|-text)?\n|view-box\n|viewport-fill(-opacity)?\n|visibility\n|visible(Fill|Painted|Stroke)?\n|wait|wavy|weight|whitespace|(device-)?width|word-spacing\n|wrap(-reverse)?\n|x{1,2}-(large|small)\n|z-index|zero\n|zoom(-in|-out)?\n|((?xi:arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|decimal-leading-zero|decimal|devanagari|disclosure-closed|disclosure-open|disc|ethiopic-numeric|georgian|gujarati|gurmukhi|hebrew|hiragana-iroha|hiragana|japanese-formal|japanese-informal|kannada|katakana-iroha|katakana|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman)))\\b", + "include": "#cubic-bezier-function" + }, + { + "include": "#steps-function" + }, + { + "comment": "animation-composition", + "match": "\\b(?:replace|add|accumulate)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-direction", + "match": "\\b(?:normal|alternate-reverse|alternate|reverse)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-fill-mode", + "match": "\\b(?:forwards|backwards|both)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-iteration-count", + "match": "\\b(?:infinite)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-play-state", + "match": "\\b(?:running|paused)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-range, animation-range-start, animation-range-end", + "match": "\\b(?:entry-crossing|exit-crossing|entry|exit)\\b", + "name": "support.constant.property-value.less" + }, + { + "comment": "animation-timing-function", + "match": "\\b(?:linear|ease-in-out|ease-in|ease-out|ease|step-start|step-end)\\b", + "name": "support.constant.property-value.less" + }, + { + "match": "(?x)\\b(\n absolute|active|add\n|all(-(petite|small)-caps|-scroll)?\n|alpha(betic)?\n|alternate(-reverse)?\n|always|annotation|antialiased|at\n|auto(hiding-scrollbar)?\n|avoid(-column|-page|-region)?\n|background(-color|-image|-position|-size)?\n|backwards|balance|baseline|below|bevel|bicubic|bidi-override|blink\n|block(-(line-height|start|end))?\n|blur\n|bold(er)?\n|border-top-left-radius\n|border-top-right-radius\n|border-bottom-left-radius\n|border-bottom-right-radius\n|border-end-end-radius\n|border-end-start-radius\n|border-start-end-radius\n|border-start-start-radius\n|border-block-start-color\n|border-block-start-style\n|border-block-start-width\n|border-block-start\n|border-block-end-color\n|border-block-end-style\n|border-block-end-width\n|border-block-end\n|border-block-color\n|border-block-style\n|border-block-width\n|border-block\n|border-inline-start-color\n|border-inline-start-style\n|border-inline-start-width\n|border-inline-start\n|border-inline-end-color\n|border-inline-end-style\n|border-inline-end-width\n|border-inline-end\n|border-inline-color\n|border-inline-style\n|border-inline-width\n|border-inline\n|border-top-color\n|border-top-style\n|border-top-width\n|border-top\n|border-right-color\n|border-right-style\n|border-right-width\n|border-right\n|border-bottom-color\n|border-bottom-style\n|border-bottom-width\n|border-bottom\n|border-left-color\n|border-left-style\n|border-left-width\n|border-left\n|border-image-outset\n|border-image-repeat\n|border-image-slice\n|border-image-source\n|border-image-width\n|border-image\n|border-color\n|border-style\n|border-width\n|border-radius\n|border-collapse\n|border-spacing\n|border\n|both\n|bottom\n|box(-shadow)?\n|break-(all|word|spaces)\n|brightness\n|butt(on)?\n|capitalize\n|cent(er|ral)\n|char(acter-variant)?\n|cjk-ideographic|clip|clone|close-quote\n|closest-(corner|side)\n|col-resize|collapse\n|color(-stop|-burn|-dodge)?\n|column((-count|-gap|-reverse|-rule(-color|-width)?|-width)|s)?\n|common-ligatures|condensed|consider-shifts|contain\n|content(-box|s)?\n|contextual|contrast|cover\n|crisp(-e|E)dges\n|crop\n|cross(hair)?\n|da(rken|shed)\n|default|dense|diagonal-fractions|difference|disabled\n|discard|discretionary-ligatures|disregard-shifts\n|distribute(-all-lines|-letter|-space)?\n|dotted|double|drop-shadow\n|(nwse|nesw|ns|ew|sw|se|nw|ne|w|s|e|n)-resize\n|ease(-in-out|-in|-out)?\n|element|ellipsis|embed|end|EndColorStr|evenodd\n|exclu(de(-ruby)?|sion)\n|expanded\n|(extra|semi|ultra)-(condensed|expanded)\n|farthest-(corner|side)?\n|fill(-box|-opacity)?\n|filter\n|fit-content\n|fixed\n|flat\n|flex((-basis|-end|-grow|-shrink|-start)|box)?\n|flip|flood-color\n|font(-size(-adjust)?|-stretch|-weight)?\n|forwards\n|from(-image)?\n|full-width|gap|geometricPrecision|glyphs|gradient|grayscale\n|grid((-column|-row)?-gap|-height)?\n|groove|hand|hanging|hard-light|height|help|hidden|hide\n|historical-(forms|ligatures)\n|horizontal(-tb)?\n|hue\n|ideograph(-alpha|-numeric|-parenthesis|-space|ic)\n|inactive|include-ruby|infinite|inherit|initial\n|inline(-(block|box|flex(box)?|line-height|table|start|end))?\n|inset|inside\n|inter(-ideograph|-word|sect)\n|invert|isolat(e|ion)|italic\n|jis(04|78|83|90)\n|justify(-all)?\n|keep-all\n|large[r]?\n|last|layout|left|letter-spacing\n|light(e[nr]|ing-color)\n|line(-edge|-height|-through)?\n|linear(-gradient|RGB)?\n|lining-nums|list-item|local|loose|lowercase|lr-tb|ltr\n|lumin(osity|ance)|manual\n|manipulation\n|margin(-bottom|-box|-left|-right|-top)?\n|marker(-offset|s)?\n|match-parent\n|mathematical\n|max-(content|height|lines|size|width)\n|medium|middle\n|min-(content|height|width)\n|miter|mixed|move|multiply|newspaper\n|no-(change|clip|(close|open)-quote|(common|discretionary|historical)-ligatures|contextual|drop|repeat)\n|none|nonzero|normal|not-allowed|nowrap|oblique\n|offset(-after|-before|-end|-start)?\n|oldstyle-nums|opacity|open-quote\n|optimize(Legibility|Precision|Quality|Speed)\n|order|ordinal|ornaments\n|outline(-color|-offset|-width)?\n|outset|outside|over(line|-edge|lay)\n|padding(-bottom|-box|-left|-right|-top|-box)?\n|page|paint(ed)?|paused\n|pan-(x|left|right|y|up|down)\n|perspective-origin\n|petite-caps|pixelated|pointer\n|pinch-zoom\n|pretty\n|pre(-line|-wrap)?\n|preserve(-3d|-breaks|-spaces)?\n|progid:DXImageTransform.Microsoft.(Alpha|Blur|dropshadow|gradient|Shadow)\n|progress\n|proportional-(nums|width)\n|radial-gradient|recto|region|relative\n|repeat(-[xy])?\n|repeating-(linear|radial)-gradient\n|replaced|reset-size|reverse|revert(-layer)?|ridge|right\n|round\n|row(-gap|-resize|-reverse)?\n|rtl|ruby|running|saturat(e|ion)|screen\n|scroll(-position|bar)?\n|separate|sepia\n|scale-down\n|shape-(image-threshold|margin|outside)\n|show\n|sideways(-lr|-rl)?\n|simplified\n|size\n|slashed-zero|slice\n|small(-caps|er)?\n|smooth|snap|solid|soft-light\n|space(-around|-between)?\n|span|sRGB\n|stable\n|stack(ed-fractions)?\n|start(ColorStr)?\n|static\n|step-(end|start)\n|sticky\n|stop-(color|opacity)\n|stretch|strict\n|stroke(-box|-dash(array|offset)|-miterlimit|-opacity|-width)?\n|style(set)?\n|stylistic\n|sub(grid|pixel-antialiased|tract)?\n|super|swash\n|table(-caption|-cell|(-column|-footer|-header|-row)-group|-column|-row)?\n|tabular-nums|tb-rl\n|text((-bottom|-(decoration|emphasis)-color|-indent|-(over|under)-edge|-shadow|-size(-adjust)?|-top)|field)?\n|thi(ck|n)\n|titling-ca(ps|se)\n|to[p]?\n|touch|traditional\n|transform(-origin)?\n|under(-edge|line)?\n|unicase|unset|uppercase|upright\n|use-(glyph-orientation|script)\n|verso\n|vertical(-align|-ideographic|-lr|-rl|-text)?\n|view-box\n|viewport-fill(-opacity)?\n|visibility\n|visible(Fill|Painted|Stroke)?\n|wait|wavy|weight|whitespace|(device-)?width|word-spacing\n|wrap(-reverse)?\n|x{1,2}-(large|small)\n|z-index|zero\n|zoom(-in|-out)?\n|((?xi:arabic-indic|armenian|bengali|cambodian|circle|cjk-decimal|cjk-earthly-branch|cjk-heavenly-stem|decimal-leading-zero|decimal|devanagari|disclosure-closed|disclosure-open|disc|ethiopic-numeric|georgian|gujarati|gurmukhi|hebrew|hiragana-iroha|hiragana|japanese-formal|japanese-informal|kannada|katakana-iroha|katakana|khmer|korean-hangul-formal|korean-hanja-formal|korean-hanja-informal|lao|lower-alpha|lower-armenian|lower-greek|lower-latin|lower-roman|malayalam|mongolian|myanmar|oriya|persian|simp-chinese-formal|simp-chinese-informal|square|tamil|telugu|thai|tibetan|trad-chinese-formal|trad-chinese-informal|upper-alpha|upper-armenian|upper-latin|upper-roman)))\\b", "name": "support.constant.property-value.less" }, { @@ -3566,13 +3738,7 @@ "include": "#comma-delimiter" }, { - "captures": { - "1": { - "name": "punctuation.separator.less" - } - }, - "match": "(\\!)\\s*important", - "name": "keyword.other.important.less" + "include": "#important" } ] }, @@ -3830,6 +3996,18 @@ } ] }, + "relative-color": { + "patterns": [ + { + "match": "from", + "name": "keyword.other.less" + }, + { + "match": "\\b[hslawbch]\\b", + "name": "keyword.other.less" + } + ] + }, "resolution-type": { "captures": { "1": { @@ -3899,6 +4077,41 @@ { "include": "#filter-function" }, + { + "begin": "\\b(border((-(bottom|top)-(left|right))|((-(start|end)){2}))?-radius|(border-image(?!-)))\\b", + "beginCaptures": { + "0": { + "name": "support.type.property-name.less" + } + }, + "comment": "border-radius and border-image properties utilize a slash as a separator", + "end": "\\s*(;)|(?=[})])", + "endCaptures": { + "1": { + "name": "punctuation.terminator.rule.less" + } + }, + "patterns": [ + { + "begin": "(((\\+_?)?):)(?=[\\s\\t]*)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.key-value.less" + } + }, + "contentName": "meta.property-value.less", + "end": "(?=\\s*(;)|(?=[})]))", + "patterns": [ + { + "include": "#value-separator" + }, + { + "include": "#property-values" + } + ] + } + ] + }, { "captures": { "1": { @@ -3951,7 +4164,7 @@ ] }, { - "begin": "\\banimation(-(delay|direction|duration|fill-mode|iteration-count|name|play-state|timing-function))?\\b", + "begin": "\\banimation-timeline\\b", "beginCaptures": { "0": { "name": "support.type.property-name.less" @@ -3971,47 +4184,91 @@ "name": "punctuation.separator.key-value.less" } }, - "captures": { + "contentName": "meta.property-value.less", + "end": "(?=\\s*(;)|(?=[})]))", + "patterns": [ + { + "include": "#comment-block" + }, + { + "include": "#custom-property-name" + }, + { + "include": "#scroll-function" + }, + { + "include": "#view-function" + }, + { + "include": "#property-values" + }, + { + "include": "#less-variables" + }, + { + "include": "#arbitrary-repetition" + }, + { + "include": "#important" + } + ] + } + ] + }, + { + "begin": "\\banimation(?:-name)?(?=(?:\\+_?)?:)\\b", + "beginCaptures": { + "0": { + "name": "support.type.property-name.less" + } + }, + "end": "\\s*(;)|(?=[})])", + "endCaptures": { + "1": { + "name": "punctuation.terminator.rule.less" + } + }, + "patterns": [ + { + "begin": "(((\\+_?)?):)(?=[\\s\\t]*)", + "beginCaptures": { "1": { - "name": "punctuation.definition.arbitrary-repetition.less" + "name": "punctuation.separator.key-value.less" } }, "contentName": "meta.property-value.less", "end": "(?=\\s*(;)|(?=[})]))", "patterns": [ { - "match": "\\b(linear|ease(-in)?(-out)?|step-(start|end)|none|forwards|backwards|both|normal|alternate(-reverse)?|reverse|running|paused)\\b", - "name": "support.constant.property-value.less" + "include": "#comment-block" }, { - "include": "#cubic-bezier-function" + "include": "#builtin-functions" }, { - "include": "#steps-function" + "include": "#less-functions" }, { - "include": "#time-type" + "include": "#less-variables" }, { - "include": "#number-type" + "include": "#numeric-values" + }, + { + "include": "#property-value-constants" }, { "match": "-?(?:[_a-zA-Z]|[^\\x{00}-\\x{7F}]|(?:(:?\\\\[0-9a-f]{1,6}(\\r\\n|[\\s\\t\\r\\n\\f])?)|\\\\[^\\r\\n\\f0-9a-f]))(?:[-_a-zA-Z0-9]|[^\\x{00}-\\x{7F}]|(?:(:?\\\\[0-9a-f]{1,6}(\\r\\n|[\\t\\r\\n\\f])?)|\\\\[^\\r\\n\\f0-9a-f]))*", - "name": "variable.other.constant.animation-name.less" + "name": "variable.other.constant.animation-name.less string.unquoted.less" }, { - "include": "#literal-string" + "include": "#less-math" }, { - "include": "#property-values" + "include": "#arbitrary-repetition" }, { - "captures": { - "1": { - "name": "punctuation.definition.arbitrary-repetition.less" - } - }, - "match": "\\s*(?:(,))" + "include": "#important" } ] } @@ -4038,11 +4295,6 @@ "name": "punctuation.separator.key-value.less" } }, - "captures": { - "1": { - "name": "punctuation.definition.arbitrary-repetition.less" - } - }, "contentName": "meta.property-value.less", "end": "(?=\\s*(;)|(?=[})]))", "patterns": [ @@ -4059,12 +4311,7 @@ "include": "#steps-function" }, { - "captures": { - "1": { - "name": "punctuation.definition.arbitrary-repetition.less" - } - }, - "match": "\\s*(?:(,))" + "include": "#arbitrary-repetition" } ] } @@ -4140,12 +4387,7 @@ "name": "support.constant.property-value.less" }, { - "captures": { - "1": { - "name": "punctuation.definition.arbitrary-repetition.less" - } - }, - "match": "\\s*(?:(,))" + "include": "#arbitrary-repetition" } ] }, @@ -4189,7 +4431,7 @@ ] }, { - "match": "(?x)\\b( accent-height | align-content | align-items | align-self | alignment-baseline | all | animation-timing-function | animation-play-state | animation-name | animation-iteration-count | animation-fill-mode | animation-duration | animation-direction | animation-delay | animation | appearance | ascent | azimuth | backface-visibility | background-size | background-repeat-y | background-repeat-x | background-repeat | background-position-y | background-position-x | background-position | background-origin | background-image | background-color | background-clip | background-blend-mode | background-attachment | background | baseline-shift | begin | bias | blend-mode | border-((top|right|bottom|left|((block|inline)(-(start|end))?))-)?(width|style|color) | border-((top|bottom)-(right|left)|((start|end)-?){1,2})-radius | border-image-(width|source|slice|repeat|outset) | border-(top|right|bottom|left|collapse|image|radius|spacing|((block|inline)(-(start|end))?)) | border | bottom | box-(align|decoration-break|direction|flex|ordinal-group|orient|pack|shadow|sizing) | break-(after|before|inside) | caption-side | clear | clip-path | clip-rule | clip | color(-(interpolation(-filters)?|profile|rendering))? | columns | column-(break-before|count|fill|gap|(rule(-(color|style|width))?)|span|width) | contain(-intrinsic-((((block|inline)-)?size)|height|width))? | content | counter-(increment|reset) | cursor | (c|d|f)(x|y) | direction | display | divisor | dominant-baseline | dur | elevation | empty-cells | enable-background | end | fallback | fill(-(opacity|rule))? | filter | flex(-(align|basis|direction|flow|grow|item-align|line-pack|negative|order|pack|positive|preferred-size|shrink|wrap))? | float | flood-(color|opacity) | font-display | font-family | font-feature-settings | font-kerning | font-language-override | font-size(-adjust)? | font-smoothing | font-stretch | font-style | font-synthesis | font-variant(-(alternates|caps|east-asian|ligatures|numeric|position))? | font-weight | font | fr | ((column|row)-)?gap | glyph-orientation-(horizontal|vertical) | grid-(area|gap) | grid-auto-(columns|flow|rows) | grid-(column|row)(-(end|gap|start))? | grid-template(-(areas|columns|rows))? | height | hyphens | image-(orientation|rendering|resolution) | inset(-(block|inline))?(-(start|end))? | isolation | justify-content | justify-items | justify-self | kerning | left | letter-spacing | lighting-color | line-(box-contain|break|clamp|height) | list-style(-(image|position|type))? | (margin|padding)(-(bottom|left|right|top)|(-(block|inline)?(-(end|start))?))? | marker(-(end|mid|start))? | mask(-(clip||composite|image|origin|position|repeat|size|type))? | (max|min)-(height|width) | mix-blend-mode | nbsp-mode | negative | object-(fit|position) | opacity | operator | order | orphans | outline(-(color|offset|style|width))? | overflow(-((inline|block)|scrolling|wrap|x|y))? | overscroll-behavior(-block|-(inline|x|y))? | pad(ding(-(bottom|left|right|top))?)? | page(-break-(after|before|inside))? | paint-order | pause(-(after|before))? | perspective(-origin(-(x|y))?)? | pitch(-range)? | place-content | place-self | pointer-events | position | prefix | quotes | range | resize | right | rotate | scale | scroll-behavior | shape-(image-threshold|margin|outside|rendering) | size | speak(-as)? | src | stop-(color|opacity) | stroke(-(dash(array|offset)|line(cap|join)|miterlimit|opacity|width))? | suffix | symbols | system | tab-size | table-layout | tap-highlight-color | text-align(-last)? | text-decoration(-(color|line|style))? | text-emphasis(-(color|position|style))? | text-(anchor|fill-color|height|indent|justify|orientation|overflow|rendering|size-adjust|shadow|transform|underline-position|wrap) | top | touch-action | transform(-origin(-(x|y))?) | transform(-style)? | transition(-(delay|duration|property|timing-function))? | translate | unicode-(bidi|range) | user-(drag|select) | vertical-align | visibility | white-space(-collapse)? | widows | width | will-change | word-(break|spacing|wrap) | writing-mode | z-index | zoom )\\b", + "match": "(?x)\\b( accent-height | align-content | align-items | align-self | alignment-baseline | all | animation-timing-function | animation-range-start | animation-range-end | animation-range | animation-play-state | animation-name | animation-iteration-count | animation-fill-mode | animation-duration | animation-direction | animation-delay | animation-composition | animation | appearance | ascent | azimuth | backface-visibility | background-size | background-repeat-y | background-repeat-x | background-repeat | background-position-y | background-position-x | background-position | background-origin | background-image | background-color | background-clip | background-blend-mode | background-attachment | background | baseline-shift | begin | bias | blend-mode | border-top-left-radius | border-top-right-radius | border-bottom-left-radius | border-bottom-right-radius | border-end-end-radius | border-end-start-radius | border-start-end-radius | border-start-start-radius | border-block-start-color | border-block-start-style | border-block-start-width | border-block-start | border-block-end-color | border-block-end-style | border-block-end-width | border-block-end | border-block-color | border-block-style | border-block-width | border-block | border-inline-start-color | border-inline-start-style | border-inline-start-width | border-inline-start | border-inline-end-color | border-inline-end-style | border-inline-end-width | border-inline-end | border-inline-color | border-inline-style | border-inline-width | border-inline | border-top-color | border-top-style | border-top-width | border-top | border-right-color | border-right-style | border-right-width | border-right | border-bottom-color | border-bottom-style | border-bottom-width | border-bottom | border-left-color | border-left-style | border-left-width | border-left | border-image-outset | border-image-repeat | border-image-slice | border-image-source | border-image-width | border-image | border-color | border-style | border-width | border-radius | border-collapse | border-spacing | border | bottom | box-(align|decoration-break|direction|flex|ordinal-group|orient|pack|shadow|sizing) | break-(after|before|inside) | caption-side | clear | clip-path | clip-rule | clip | color(-(interpolation(-filters)?|profile|rendering))? | columns | column-(break-before|count|fill|gap|(rule(-(color|style|width))?)|span|width) | contain(-intrinsic-((((block|inline)-)?size)|height|width))? | content | counter-(increment|reset) | cursor | (c|d|f)(x|y) | direction | display | divisor | dominant-baseline | dur | elevation | empty-cells | enable-background | end | fallback | fill(-(opacity|rule))? | filter | flex(-(align|basis|direction|flow|grow|item-align|line-pack|negative|order|pack|positive|preferred-size|shrink|wrap))? | float | flood-(color|opacity) | font-display | font-family | font-feature-settings | font-kerning | font-language-override | font-size(-adjust)? | font-smoothing | font-stretch | font-style | font-synthesis | font-variant(-(alternates|caps|east-asian|ligatures|numeric|position))? | font-weight | font | fr | ((column|row)-)?gap | glyph-orientation-(horizontal|vertical) | grid-(area|gap) | grid-auto-(columns|flow|rows) | grid-(column|row)(-(end|gap|start))? | grid-template(-(areas|columns|rows))? | height | hyphens | image-(orientation|rendering|resolution) | inset(-(block|inline))?(-(start|end))? | isolation | justify-content | justify-items | justify-self | kerning | left | letter-spacing | lighting-color | line-(box-contain|break|clamp|height) | list-style(-(image|position|type))? | (margin|padding)(-(bottom|left|right|top)|(-(block|inline)?(-(end|start))?))? | marker(-(end|mid|start))? | mask(-(clip||composite|image|origin|position|repeat|size|type))? | (max|min)-(height|width) | mix-blend-mode | nbsp-mode | negative | object-(fit|position) | opacity | operator | order | orphans | outline(-(color|offset|style|width))? | overflow(-((inline|block)|scrolling|wrap|x|y))? | overscroll-behavior(-block|-(inline|x|y))? | pad(ding(-(bottom|left|right|top))?)? | page(-break-(after|before|inside))? | paint-order | pause(-(after|before))? | perspective(-origin(-(x|y))?)? | pitch(-range)? | place-content | place-self | pointer-events | position | prefix | quotes | range | resize | right | rotate | scale | scroll-behavior | shape-(image-threshold|margin|outside|rendering) | size | speak(-as)? | src | stop-(color|opacity) | stroke(-(dash(array|offset)|line(cap|join)|miterlimit|opacity|width))? | suffix | symbols | system | tab-size | table-layout | tap-highlight-color | text-align(-last)? | text-decoration(-(color|line|style))? | text-emphasis(-(color|position|style))? | text-(anchor|fill-color|height|indent|justify|orientation|overflow|rendering|size-adjust|shadow|transform|underline-position|wrap) | top | touch-action | transform(-origin(-(x|y))?) | transform(-style)? | transition(-(delay|duration|property|timing-function))? | translate | unicode-(bidi|range) | user-(drag|select) | vertical-align | visibility | white-space(-collapse)? | widows | width | will-change | word-(break|spacing|wrap) | writing-mode | z-index | zoom )\\b", "name": "support.type.property-name.less" }, { @@ -4237,6 +4479,40 @@ } ] }, + "scroll-function": { + "begin": "\\b(scroll)(\\()", + "beginCaptures": { + "1": { + "name": "support.function.scroll.less" + }, + "2": { + "name": "punctuation.definition.group.begin.less" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.end.less" + } + }, + "name": "meta.function-call.less", + "patterns": [ + { + "match": "root|nearest|self", + "name": "support.constant.scroller.less" + }, + { + "match": "block|inline|x|y", + "name": "support.constant.axis.less" + }, + { + "include": "#less-variables" + }, + { + "include": "#var-function" + } + ] + }, "selector": { "patterns": [ { @@ -4257,13 +4533,7 @@ "include": "#less-variable-interpolation" }, { - "captures": { - "1": { - "name": "punctuation.separator.less" - } - }, - "match": "(\\!)\\s*important", - "name": "keyword.other.important.less" + "include": "#important" } ] } @@ -4405,12 +4675,7 @@ ] }, { - "captures": { - "1": { - "name": "punctuation.definition.arbitrary-repetition.less" - } - }, - "match": "\\s*(?:(,))" + "include": "#arbitrary-repetition" }, { "match": "\\*", @@ -4579,12 +4844,16 @@ ] }, "steps-function": { - "begin": "\\b(steps)(?=\\()", + "begin": "\\b(steps)(\\()", "beginCaptures": { - "0": { + "1": { "name": "support.function.timing.less" + }, + "2": { + "name": "punctuation.definition.group.begin.less" } }, + "contentName": "meta.group.less", "end": "\\)", "endCaptures": { "0": { @@ -4594,25 +4863,23 @@ "name": "meta.function-call.less", "patterns": [ { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.group.begin.less" - } - }, - "end": "(?=\\))", - "patterns": [ - { - "include": "#comma-delimiter" - }, - { - "include": "#integer-type" - }, - { - "match": "(end|middle|start)", - "name": "support.keyword.timing-direction.less" - } - ] + "match": "jump-start|jump-end|jump-none|jump-both|start|end", + "name": "support.constant.step-position.less" + }, + { + "include": "#comma-delimiter" + }, + { + "include": "#integer-type" + }, + { + "include": "#less-variables" + }, + { + "include": "#var-function" + }, + { + "include": "#calc-function" } ] }, @@ -5085,45 +5352,49 @@ } ] }, + "value-separator": { + "captures": { + "1": { + "name": "punctuation.separator.less" + } + }, + "match": "\\s*(/)\\s*" + }, "var-function": { + "begin": "\\b(var)(?=\\()", + "beginCaptures": { + "1": { + "name": "support.function.var.less" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.end.less" + } + }, + "name": "meta.function-call.less", "patterns": [ { - "begin": "\\b(var)(?=\\()", + "begin": "\\(", "beginCaptures": { - "1": { - "name": "support.function.var.less" - } - }, - "end": "\\)", - "endCaptures": { "0": { - "name": "punctuation.definition.group.end.less" + "name": "punctuation.definition.group.begin.less" } }, - "name": "meta.function-call.less", + "end": "(?=\\))", "patterns": [ { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.group.begin.less" - } - }, - "end": "(?=\\))", - "patterns": [ - { - "include": "#comma-delimiter" - }, - { - "include": "#custom-property-name" - }, - { - "include": "#less-variables" - }, - { - "include": "#property-values" - } - ] + "include": "#comma-delimiter" + }, + { + "include": "#custom-property-name" + }, + { + "include": "#less-variables" + }, + { + "include": "#property-values" } ] } @@ -5132,6 +5403,56 @@ "vendor-prefix": { "match": "-(?:webkit|moz(-osx)?|ms|o)-", "name": "support.type.vendor-prefix.less" + }, + "view-function": { + "begin": "\\b(view)(?=\\()", + "beginCaptures": { + "1": { + "name": "support.function.view.less" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.group.end.less" + } + }, + "name": "meta.function-call.less", + "patterns": [ + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.group.begin.less" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "match": "block|inline|x|y|auto", + "name": "support.constant.property-value.less" + }, + { + "include": "#length-type" + }, + { + "include": "#percentage-type" + }, + { + "include": "#less-variables" + }, + { + "include": "#var-function" + }, + { + "include": "#calc-function" + }, + { + "include": "#arbitrary-repetition" + } + ] + } + ] } } } \ No newline at end of file diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index f06dd4233c8..894c1035c39 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -772,7 +772,7 @@ "picomatch": "^2.3.1", "vscode-languageclient": "^8.0.2", "vscode-languageserver-textdocument": "^1.0.11", - "vscode-markdown-languageserver": "^0.5.0-alpha.7", + "vscode-markdown-languageserver": "^0.5.0-alpha.8", "vscode-uri": "^3.0.3" }, "devDependencies": { diff --git a/extensions/markdown-language-features/src/extension.ts b/extensions/markdown-language-features/src/extension.ts index b5a42ed9a95..98ea87df069 100644 --- a/extensions/markdown-language-features/src/extension.ts +++ b/extensions/markdown-language-features/src/extension.ts @@ -31,6 +31,8 @@ function startServer(context: vscode.ExtensionContext, parser: IMdParser): Promi const serverModule = context.asAbsolutePath( isDebugBuild + // For local non bundled version of vscode-markdown-languageserver + // ? './node_modules/vscode-markdown-languageserver/out/node/workerMain' ? './node_modules/vscode-markdown-languageserver/dist/node/workerMain' : './dist/serverWorkerMain' ); diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index 69f7733816e..525795036ab 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -453,16 +453,16 @@ vscode-languageserver@^8.1.0: dependencies: vscode-languageserver-protocol "3.17.3" -vscode-markdown-languageserver@^0.5.0-alpha.7: - version "0.5.0-alpha.7" - resolved "https://registry.yarnpkg.com/vscode-markdown-languageserver/-/vscode-markdown-languageserver-0.5.0-alpha.7.tgz#7db060e3e2f5ec5afae7801c9a8e77ed92ff09ae" - integrity sha512-PkJMlZ4B7dUGSQIaLabXx00Hg2PFYuoi1lp2kAJu51TUEbt/B7J3u/7MhwbDXx3ZQga3TSfrPJ+V/SOBQiP/Xw== +vscode-markdown-languageserver@^0.5.0-alpha.8: + version "0.5.0-alpha.8" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageserver/-/vscode-markdown-languageserver-0.5.0-alpha.8.tgz#87ced4b241636b6aeda7aacc41badced0c2cc992" + integrity sha512-Bp6YXHy4EMQ8JpsmXpQHa78byLvv83wVnLmhVfTaJsZTBwF8IOJ56NBUasepg9L6QVffUA9T2H/PfBqEOGpeOQ== dependencies: "@vscode/l10n" "^0.0.11" vscode-languageserver "^8.1.0" vscode-languageserver-textdocument "^1.0.8" vscode-languageserver-types "^3.17.3" - vscode-markdown-languageservice "^0.5.0-alpha.6" + vscode-markdown-languageservice "^0.5.0-alpha.7" vscode-uri "^3.0.7" vscode-markdown-languageservice@^0.3.0-alpha.3: @@ -476,10 +476,10 @@ vscode-markdown-languageservice@^0.3.0-alpha.3: vscode-languageserver-types "^3.17.1" vscode-uri "^3.0.3" -vscode-markdown-languageservice@^0.5.0-alpha.6: - version "0.5.0-alpha.6" - resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.5.0-alpha.6.tgz#3aa5fc94fea3d5d7f0cd970e64348e2791643dc0" - integrity sha512-mA1JCA7aHHSek5gr8Yv7C3esEPo2hRrgxmoZUDRro+pnwbdsJuRaWOKWtCWxejRUVVVhc/5yTK2X64Jx9OCmFQ== +vscode-markdown-languageservice@^0.5.0-alpha.7: + version "0.5.0-alpha.7" + resolved "https://registry.yarnpkg.com/vscode-markdown-languageservice/-/vscode-markdown-languageservice-0.5.0-alpha.7.tgz#0cc0939ea803d2afcb7a6e99b55feec664ec1b37" + integrity sha512-Iq9S5YGHm3D/UG9Usm8a/O5tYCo9FwaMF7nJsDQCxKgVZu5OzwOj3ixDkhoM+c8GKXiwt23DxhhWRuvI4odkTg== dependencies: "@vscode/l10n" "^0.0.10" node-html-parser "^6.1.5" diff --git a/extensions/microsoft-authentication/extension-browser.webpack.config.js b/extensions/microsoft-authentication/extension-browser.webpack.config.js index c0f4b92069f..0d395fc0f96 100644 --- a/extensions/microsoft-authentication/extension-browser.webpack.config.js +++ b/extensions/microsoft-authentication/extension-browser.webpack.config.js @@ -23,7 +23,8 @@ module.exports = withBrowserDefaults({ resolve: { alias: { './node/authServer': path.resolve(__dirname, 'src/browser/authServer'), - './node/buffer': path.resolve(__dirname, 'src/browser/buffer') + './node/buffer': path.resolve(__dirname, 'src/browser/buffer'), + './node/authProvider': path.resolve(__dirname, 'src/browser/authProvider'), } } }); diff --git a/extensions/microsoft-authentication/package.json b/extensions/microsoft-authentication/package.json index af46f732d92..ad6a4d5cb71 100644 --- a/extensions/microsoft-authentication/package.json +++ b/extensions/microsoft-authentication/package.json @@ -14,8 +14,7 @@ ], "activationEvents": [], "enabledApiProposals": [ - "idToken", - "authGetSessions" + "idToken" ], "capabilities": { "virtualWorkspaces": true, @@ -96,6 +95,15 @@ ] } } + }, + { + "title": "Microsoft", + "properties": { + "microsoft.useMsal": { + "type": "boolean", + "description": "%useMsal.description%" + } + } } ] }, @@ -118,7 +126,9 @@ }, "dependencies": { "@azure/ms-rest-azure-env": "^2.0.0", - "@vscode/extension-telemetry": "^0.9.0" + "@azure/msal-node": "^2.13.0", + "@vscode/extension-telemetry": "^0.9.0", + "vscode-tas-client": "^0.1.84" }, "repository": { "type": "git", diff --git a/extensions/microsoft-authentication/package.nls.json b/extensions/microsoft-authentication/package.nls.json index 14c625dc762..80cbb32d4ab 100644 --- a/extensions/microsoft-authentication/package.nls.json +++ b/extensions/microsoft-authentication/package.nls.json @@ -3,6 +3,7 @@ "description": "Microsoft authentication provider", "signIn": "Sign In", "signOut": "Sign Out", + "useMsal.description": "Use the Microsoft Authentication Library (MSAL) to sign in with a Microsoft account.", "microsoft-sovereign-cloud.environment.description": { "message": "The Sovereign Cloud to use for authentication. If you select `custom`, you must also set the `#microsoft-sovereign-cloud.customEnvironment#` setting.", "comment": [ diff --git a/extensions/microsoft-authentication/src/UriEventHandler.ts b/extensions/microsoft-authentication/src/UriEventHandler.ts index 3dc753af835..f525912fa51 100644 --- a/extensions/microsoft-authentication/src/UriEventHandler.ts +++ b/extensions/microsoft-authentication/src/UriEventHandler.ts @@ -6,7 +6,14 @@ import * as vscode from 'vscode'; export class UriEventHandler extends vscode.EventEmitter implements vscode.UriHandler { - public handleUri(uri: vscode.Uri) { + private _disposable = vscode.window.registerUriHandler(this); + + handleUri(uri: vscode.Uri) { this.fire(uri); } + + override dispose(): void { + super.dispose(); + this._disposable.dispose(); + } } diff --git a/extensions/microsoft-authentication/src/browser/authProvider.ts b/extensions/microsoft-authentication/src/browser/authProvider.ts new file mode 100644 index 00000000000..3b4da5b18fa --- /dev/null +++ b/extensions/microsoft-authentication/src/browser/authProvider.ts @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AuthenticationProvider, AuthenticationProviderAuthenticationSessionsChangeEvent, AuthenticationSession, EventEmitter } from 'vscode'; + +export class MsalAuthProvider implements AuthenticationProvider { + private _onDidChangeSessions = new EventEmitter(); + onDidChangeSessions = this._onDidChangeSessions.event; + + initialize(): Thenable { + throw new Error('Method not implemented.'); + } + + getSessions(): Thenable { + throw new Error('Method not implemented.'); + } + createSession(): Thenable { + throw new Error('Method not implemented.'); + } + removeSession(): Thenable { + throw new Error('Method not implemented.'); + } + + dispose() { + this._onDidChangeSessions.dispose(); + } +} diff --git a/extensions/microsoft-authentication/src/common/async.ts b/extensions/microsoft-authentication/src/common/async.ts index 641faaff0dd..094861518fc 100644 --- a/extensions/microsoft-authentication/src/common/async.ts +++ b/extensions/microsoft-authentication/src/common/async.ts @@ -3,7 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationError, CancellationToken, Disposable } from 'vscode'; +import { CancellationError, CancellationToken, Disposable, Event, EventEmitter } from 'vscode'; + +/** + * Can be passed into the Delayed to defer using a microtask + */ +export const MicrotaskDelay = Symbol('MicrotaskDelay'); export class SequencerByKey { @@ -80,3 +85,473 @@ export function raceTimeoutError(promise: Promise, timeout: number): Promi export function raceCancellationAndTimeoutError(promise: Promise, token: CancellationToken, timeout: number): Promise { return raceCancellationError(raceTimeoutError(promise, timeout), token); } + +interface ILimitedTaskFactory { + factory: () => Promise; + c: (value: T | Promise) => void; + e: (error?: unknown) => void; +} + +export interface ILimiter { + + readonly size: number; + + queue(factory: () => Promise): Promise; + + clear(): void; +} + +/** + * A helper to queue N promises and run them all with a max degree of parallelism. The helper + * ensures that at any time no more than M promises are running at the same time. + */ +export class Limiter implements ILimiter { + + private _size = 0; + private _isDisposed = false; + private runningPromises: number; + private readonly maxDegreeOfParalellism: number; + private readonly outstandingPromises: ILimitedTaskFactory[]; + private readonly _onDrained: EventEmitter; + + constructor(maxDegreeOfParalellism: number) { + this.maxDegreeOfParalellism = maxDegreeOfParalellism; + this.outstandingPromises = []; + this.runningPromises = 0; + this._onDrained = new EventEmitter(); + } + + /** + * + * @returns A promise that resolved when all work is done (onDrained) or when + * there is nothing to do + */ + whenIdle(): Promise { + return this.size > 0 + ? toPromise(this.onDrained) + : Promise.resolve(); + } + + get onDrained(): Event { + return this._onDrained.event; + } + + get size(): number { + return this._size; + } + + queue(factory: () => Promise): Promise { + if (this._isDisposed) { + throw new Error('Object has been disposed'); + } + this._size++; + + return new Promise((c, e) => { + this.outstandingPromises.push({ factory, c, e }); + this.consume(); + }); + } + + private consume(): void { + while (this.outstandingPromises.length && this.runningPromises < this.maxDegreeOfParalellism) { + const iLimitedTask = this.outstandingPromises.shift()!; + this.runningPromises++; + + const promise = iLimitedTask.factory(); + promise.then(iLimitedTask.c, iLimitedTask.e); + promise.then(() => this.consumed(), () => this.consumed()); + } + } + + private consumed(): void { + if (this._isDisposed) { + return; + } + this.runningPromises--; + if (--this._size === 0) { + this._onDrained.fire(); + } + + if (this.outstandingPromises.length > 0) { + this.consume(); + } + } + + clear(): void { + if (this._isDisposed) { + throw new Error('Object has been disposed'); + } + this.outstandingPromises.length = 0; + this._size = this.runningPromises; + } + + dispose(): void { + this._isDisposed = true; + this.outstandingPromises.length = 0; // stop further processing + this._size = 0; + this._onDrained.dispose(); + } +} + + +interface IScheduledLater extends Disposable { + isTriggered(): boolean; +} + +const timeoutDeferred = (timeout: number, fn: () => void): IScheduledLater => { + let scheduled = true; + const handle = setTimeout(() => { + scheduled = false; + fn(); + }, timeout); + return { + isTriggered: () => scheduled, + dispose: () => { + clearTimeout(handle); + scheduled = false; + }, + }; +}; + +const microtaskDeferred = (fn: () => void): IScheduledLater => { + let scheduled = true; + queueMicrotask(() => { + if (scheduled) { + scheduled = false; + fn(); + } + }); + + return { + isTriggered: () => scheduled, + dispose: () => { scheduled = false; }, + }; +}; + +/** + * A helper to delay (debounce) execution of a task that is being requested often. + * + * Following the throttler, now imagine the mail man wants to optimize the number of + * trips proactively. The trip itself can be long, so he decides not to make the trip + * as soon as a letter is submitted. Instead he waits a while, in case more + * letters are submitted. After said waiting period, if no letters were submitted, he + * decides to make the trip. Imagine that N more letters were submitted after the first + * one, all within a short period of time between each other. Even though N+1 + * submissions occurred, only 1 delivery was made. + * + * The delayer offers this behavior via the trigger() method, into which both the task + * to be executed and the waiting period (delay) must be passed in as arguments. Following + * the example: + * + * const delayer = new Delayer(WAITING_PERIOD); + * const letters = []; + * + * function letterReceived(l) { + * letters.push(l); + * delayer.trigger(() => { return makeTheTrip(); }); + * } + */ +export class Delayer implements Disposable { + + private deferred: IScheduledLater | null; + private completionPromise: Promise | null; + private doResolve: ((value?: any | Promise) => void) | null; + private doReject: ((err: any) => void) | null; + private task: (() => T | Promise) | null; + + constructor(public defaultDelay: number | typeof MicrotaskDelay) { + this.deferred = null; + this.completionPromise = null; + this.doResolve = null; + this.doReject = null; + this.task = null; + } + + trigger(task: () => T | Promise, delay = this.defaultDelay): Promise { + this.task = task; + this.cancelTimeout(); + + if (!this.completionPromise) { + this.completionPromise = new Promise((resolve, reject) => { + this.doResolve = resolve; + this.doReject = reject; + }).then(() => { + this.completionPromise = null; + this.doResolve = null; + if (this.task) { + const task = this.task; + this.task = null; + return task(); + } + return undefined; + }); + } + + const fn = () => { + this.deferred = null; + this.doResolve?.(null); + }; + + this.deferred = delay === MicrotaskDelay ? microtaskDeferred(fn) : timeoutDeferred(delay, fn); + + return this.completionPromise; + } + + isTriggered(): boolean { + return !!this.deferred?.isTriggered(); + } + + cancel(): void { + this.cancelTimeout(); + + if (this.completionPromise) { + this.doReject?.(new CancellationError()); + this.completionPromise = null; + } + } + + private cancelTimeout(): void { + this.deferred?.dispose(); + this.deferred = null; + } + + dispose(): void { + this.cancel(); + } +} + +/** + * A helper to prevent accumulation of sequential async tasks. + * + * Imagine a mail man with the sole task of delivering letters. As soon as + * a letter submitted for delivery, he drives to the destination, delivers it + * and returns to his base. Imagine that during the trip, N more letters were submitted. + * When the mail man returns, he picks those N letters and delivers them all in a + * single trip. Even though N+1 submissions occurred, only 2 deliveries were made. + * + * The throttler implements this via the queue() method, by providing it a task + * factory. Following the example: + * + * const throttler = new Throttler(); + * const letters = []; + * + * function deliver() { + * const lettersToDeliver = letters; + * letters = []; + * return makeTheTrip(lettersToDeliver); + * } + * + * function onLetterReceived(l) { + * letters.push(l); + * throttler.queue(deliver); + * } + */ +export class Throttler implements Disposable { + + private activePromise: Promise | null; + private queuedPromise: Promise | null; + private queuedPromiseFactory: (() => Promise) | null; + + private isDisposed = false; + + constructor() { + this.activePromise = null; + this.queuedPromise = null; + this.queuedPromiseFactory = null; + } + + queue(promiseFactory: () => Promise): Promise { + if (this.isDisposed) { + return Promise.reject(new Error('Throttler is disposed')); + } + + if (this.activePromise) { + this.queuedPromiseFactory = promiseFactory; + + if (!this.queuedPromise) { + const onComplete = () => { + this.queuedPromise = null; + + if (this.isDisposed) { + return; + } + + const result = this.queue(this.queuedPromiseFactory!); + this.queuedPromiseFactory = null; + + return result; + }; + + this.queuedPromise = new Promise(resolve => { + this.activePromise!.then(onComplete, onComplete).then(resolve); + }); + } + + return new Promise((resolve, reject) => { + this.queuedPromise!.then(resolve, reject); + }); + } + + this.activePromise = promiseFactory(); + + return new Promise((resolve, reject) => { + this.activePromise!.then((result: T) => { + this.activePromise = null; + resolve(result); + }, (err: unknown) => { + this.activePromise = null; + reject(err); + }); + }); + } + + dispose(): void { + this.isDisposed = true; + } +} + +/** + * A helper to delay execution of a task that is being requested often, while + * preventing accumulation of consecutive executions, while the task runs. + * + * The mail man is clever and waits for a certain amount of time, before going + * out to deliver letters. While the mail man is going out, more letters arrive + * and can only be delivered once he is back. Once he is back the mail man will + * do one more trip to deliver the letters that have accumulated while he was out. + */ +export class ThrottledDelayer { + + private delayer: Delayer>; + private throttler: Throttler; + + constructor(defaultDelay: number) { + this.delayer = new Delayer(defaultDelay); + this.throttler = new Throttler(); + } + + trigger(promiseFactory: () => Promise, delay?: number): Promise { + return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as unknown as Promise; + } + + isTriggered(): boolean { + return this.delayer.isTriggered(); + } + + cancel(): void { + this.delayer.cancel(); + } + + dispose(): void { + this.delayer.dispose(); + this.throttler.dispose(); + } +} + +/** + * A queue is handles one promise at a time and guarantees that at any time only one promise is executing. + */ +export class Queue extends Limiter { + + constructor() { + super(1); + } +} + +/** + * Given an event, returns another event which only fires once. + * + * @param event The event source for the new event. + */ +export function once(event: Event): Event { + return (listener, thisArgs = null, disposables?) => { + // we need this, in case the event fires during the listener call + let didFire = false; + let result: Disposable | undefined = undefined; + result = event(e => { + if (didFire) { + return; + } else if (result) { + result.dispose(); + } else { + didFire = true; + } + + return listener.call(thisArgs, e); + }, null, disposables); + + if (didFire) { + result.dispose(); + } + + return result; + }; +} + +/** + * Creates a promise out of an event, using the {@link Event.once} helper. + */ +export function toPromise(event: Event): Promise { + return new Promise(resolve => once(event)(resolve)); +} + +export type ValueCallback = (value: T | Promise) => void; + +const enum DeferredOutcome { + Resolved, + Rejected +} + +/** + * Creates a promise whose resolution or rejection can be controlled imperatively. + */ +export class DeferredPromise { + + private completeCallback!: ValueCallback; + private errorCallback!: (err: unknown) => void; + private outcome?: { outcome: DeferredOutcome.Rejected; value: any } | { outcome: DeferredOutcome.Resolved; value: T }; + + public get isRejected() { + return this.outcome?.outcome === DeferredOutcome.Rejected; + } + + public get isResolved() { + return this.outcome?.outcome === DeferredOutcome.Resolved; + } + + public get isSettled() { + return !!this.outcome; + } + + public get value() { + return this.outcome?.outcome === DeferredOutcome.Resolved ? this.outcome?.value : undefined; + } + + public readonly p: Promise; + + constructor() { + this.p = new Promise((c, e) => { + this.completeCallback = c; + this.errorCallback = e; + }); + } + + public complete(value: T) { + return new Promise(resolve => { + this.completeCallback(value); + this.outcome = { outcome: DeferredOutcome.Resolved, value }; + resolve(); + }); + } + + public error(err: unknown) { + return new Promise(resolve => { + this.errorCallback(err); + this.outcome = { outcome: DeferredOutcome.Rejected, value: err }; + resolve(); + }); + } + + public cancel() { + return this.error(new CancellationError()); + } +} diff --git a/extensions/microsoft-authentication/src/common/cachePlugin.ts b/extensions/microsoft-authentication/src/common/cachePlugin.ts new file mode 100644 index 00000000000..91b4f0ee6a8 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/cachePlugin.ts @@ -0,0 +1,55 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ICachePlugin, TokenCacheContext } from '@azure/msal-node'; +import { Disposable, EventEmitter, SecretStorage } from 'vscode'; + +export class SecretStorageCachePlugin implements ICachePlugin { + private readonly _onDidChange: EventEmitter = new EventEmitter(); + readonly onDidChange = this._onDidChange.event; + + private _disposable: Disposable; + + private _value: string | undefined; + + constructor( + private readonly _secretStorage: SecretStorage, + private readonly _key: string + ) { + this._disposable = Disposable.from( + this._onDidChange, + this._registerChangeHandler() + ); + } + + private _registerChangeHandler() { + return this._secretStorage.onDidChange(e => { + if (e.key === this._key) { + this._onDidChange.fire(); + } + }); + } + + async beforeCacheAccess(tokenCacheContext: TokenCacheContext): Promise { + const data = await this._secretStorage.get(this._key); + this._value = data; + if (data) { + tokenCacheContext.tokenCache.deserialize(data); + } + } + + async afterCacheAccess(tokenCacheContext: TokenCacheContext): Promise { + if (tokenCacheContext.cacheHasChanged) { + const value = tokenCacheContext.tokenCache.serialize(); + if (value !== this._value) { + await this._secretStorage.store(this._key, value); + } + } + } + + dispose() { + this._disposable.dispose(); + } +} diff --git a/extensions/microsoft-authentication/src/common/experimentation.ts b/extensions/microsoft-authentication/src/common/experimentation.ts new file mode 100644 index 00000000000..dd383c4f040 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/experimentation.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { getExperimentationService, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client'; + +export async function createExperimentationService( + context: vscode.ExtensionContext, + experimentationTelemetry: IExperimentationTelemetry, + isPreRelease: boolean, +): Promise { + const id = context.extension.id; + const version = context.extension.packageJSON['version']; + + const service = getExperimentationService( + id, + version, + isPreRelease ? TargetPopulation.Insiders : TargetPopulation.Public, + experimentationTelemetry, + context.globalState, + ) as unknown as IExperimentationService; + await service.initializePromise; + await service.initialFetch; + return service; +} diff --git a/extensions/microsoft-authentication/src/common/loggerOptions.ts b/extensions/microsoft-authentication/src/common/loggerOptions.ts new file mode 100644 index 00000000000..86443c0281f --- /dev/null +++ b/extensions/microsoft-authentication/src/common/loggerOptions.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { LogLevel as MsalLogLevel } from '@azure/msal-node'; +import { env, LogLevel, LogOutputChannel } from 'vscode'; + +export class MsalLoggerOptions { + piiLoggingEnabled = false; + + constructor(private readonly _output: LogOutputChannel) { } + + get logLevel(): MsalLogLevel { + return this._toMsalLogLevel(env.logLevel); + } + + loggerCallback(level: MsalLogLevel, message: string, containsPii: boolean): void { + if (containsPii) { + return; + } + + switch (level) { + case MsalLogLevel.Error: + this._output.error(message); + return; + case MsalLogLevel.Warning: + this._output.warn(message); + return; + case MsalLogLevel.Info: + this._output.info(message); + return; + case MsalLogLevel.Verbose: + this._output.debug(message); + return; + case MsalLogLevel.Trace: + this._output.trace(message); + return; + default: + this._output.info(message); + return; + } + } + + private _toMsalLogLevel(logLevel: LogLevel): MsalLogLevel { + switch (logLevel) { + case LogLevel.Trace: + return MsalLogLevel.Trace; + case LogLevel.Debug: + return MsalLogLevel.Verbose; + case LogLevel.Info: + return MsalLogLevel.Info; + case LogLevel.Warning: + return MsalLogLevel.Warning; + case LogLevel.Error: + return MsalLogLevel.Error; + default: + return MsalLogLevel.Info; + } + } +} diff --git a/extensions/microsoft-authentication/src/common/loopbackClientAndOpener.ts b/extensions/microsoft-authentication/src/common/loopbackClientAndOpener.ts new file mode 100644 index 00000000000..4a455ea50f7 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/loopbackClientAndOpener.ts @@ -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 type { ILoopbackClient, ServerAuthorizationCodeResponse } from '@azure/msal-node'; +import type { UriEventHandler } from '../UriEventHandler'; +import { env, Uri } from 'vscode'; +import { toPromise } from './async'; + +export interface ILoopbackClientAndOpener extends ILoopbackClient { + openBrowser(url: string): Promise; +} + +export class UriHandlerLoopbackClient implements ILoopbackClientAndOpener { + constructor( + private readonly _uriHandler: UriEventHandler, + private readonly _redirectUri: string + ) { } + + async listenForAuthCode(successTemplate?: string, errorTemplate?: string): Promise { + console.log(successTemplate, errorTemplate); + const url = await toPromise(this._uriHandler.event); + const result = new URL(url.toString(true)); + + return { + code: result.searchParams.get('code') ?? undefined, + state: result.searchParams.get('state') ?? undefined, + error: result.searchParams.get('error') ?? undefined, + error_description: result.searchParams.get('error_description') ?? undefined, + error_uri: result.searchParams.get('error_uri') ?? undefined, + }; + } + + getRedirectUri(): string { + // We always return the constant redirect URL because + // it will handle redirecting back to the extension + return this._redirectUri; + } + + closeServer(): void { + // No-op + } + + async openBrowser(url: string): Promise { + const callbackUri = await env.asExternalUri(Uri.parse(`${env.uriScheme}://vscode.microsoft-authentication`)); + + const uri = Uri.parse(url + `&state=${encodeURI(callbackUri.toString(true))}`); + await env.openExternal(uri); + } +} diff --git a/extensions/microsoft-authentication/src/common/publicClientCache.ts b/extensions/microsoft-authentication/src/common/publicClientCache.ts new file mode 100644 index 00000000000..cb9339f926d --- /dev/null +++ b/extensions/microsoft-authentication/src/common/publicClientCache.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import type { AccountInfo, AuthenticationResult, InteractiveRequest, SilentFlowRequest } from '@azure/msal-node'; +import type { Disposable, Event } from 'vscode'; + +export interface ICachedPublicClientApplication extends Disposable { + initialize(): Promise; + acquireTokenSilent(request: SilentFlowRequest): Promise; + acquireTokenInteractive(request: InteractiveRequest): Promise; + removeAccount(account: AccountInfo): Promise; + accounts: AccountInfo[]; + clientId: string; + authority: string; +} + +export interface ICachedPublicClientApplicationManager { + getOrCreate(clientId: string, authority: string): Promise; + getAll(): ICachedPublicClientApplication[]; +} diff --git a/extensions/microsoft-authentication/src/common/scopeData.ts b/extensions/microsoft-authentication/src/common/scopeData.ts new file mode 100644 index 00000000000..148658de343 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/scopeData.ts @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const DEFAULT_CLIENT_ID = 'aebc6443-996d-45c2-90f0-388ff96faa56'; +const DEFAULT_TENANT = 'organizations'; + +export class ScopeData { + + /** + * The full list of scopes including: + * * the original scopes passed to the constructor + * * internal VS Code scopes (e.g. `VSCODE_CLIENT_ID:...`) + * * the default scopes (`openid`, `email`, `profile`, `offline_access`) + */ + readonly allScopes: string[]; + + /** + * The full list of scopes as a space-separated string. For logging. + */ + readonly scopeStr: string; + + /** + * The list of scopes to send to the token endpoint. This is the same as `scopes` but without the internal VS Code scopes. + */ + readonly scopesToSend: string[]; + + /** + * The client ID to use for the token request. This is the value of the `VSCODE_CLIENT_ID:...` scope if present, otherwise the default client ID. + */ + readonly clientId: string; + + /** + * The tenant ID to use for the token request. This is the value of the `VSCODE_TENANT:...` scope if present, otherwise the default tenant ID. + */ + readonly tenant: string; + + constructor(readonly originalScopes: readonly string[] = []) { + const modifiedScopes = [...originalScopes]; + if (!modifiedScopes.includes('openid')) { + modifiedScopes.push('openid'); + } + if (!modifiedScopes.includes('email')) { + modifiedScopes.push('email'); + } + if (!modifiedScopes.includes('profile')) { + modifiedScopes.push('profile'); + } + if (!modifiedScopes.includes('offline_access')) { + modifiedScopes.push('offline_access'); + } + modifiedScopes.sort(); + this.allScopes = modifiedScopes; + this.scopeStr = modifiedScopes.join(' '); + this.scopesToSend = this.originalScopes.filter(s => !s.startsWith('VSCODE_')); + this.clientId = this.getClientId(this.allScopes); + this.tenant = this.getTenantId(this.allScopes); + } + + private getClientId(scopes: string[]) { + return scopes.reduce((prev, current) => { + if (current.startsWith('VSCODE_CLIENT_ID:')) { + return current.split('VSCODE_CLIENT_ID:')[1]; + } + return prev; + }, undefined) ?? DEFAULT_CLIENT_ID; + } + + private getTenantId(scopes: string[]) { + return scopes.reduce((prev, current) => { + if (current.startsWith('VSCODE_TENANT:')) { + return current.split('VSCODE_TENANT:')[1]; + } + return prev; + }, undefined) ?? DEFAULT_TENANT; + } +} diff --git a/extensions/microsoft-authentication/src/common/telemetryReporter.ts b/extensions/microsoft-authentication/src/common/telemetryReporter.ts new file mode 100644 index 00000000000..25ac2623282 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/telemetryReporter.ts @@ -0,0 +1,128 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import TelemetryReporter, { TelemetryEventProperties } from '@vscode/extension-telemetry'; +import { IExperimentationTelemetry } from 'vscode-tas-client'; + +export const enum MicrosoftAccountType { + AAD = 'aad', + MSA = 'msa', + Unknown = 'unknown' +} + +export class MicrosoftAuthenticationTelemetryReporter implements IExperimentationTelemetry { + private sharedProperties: Record = {}; + protected _telemetryReporter: TelemetryReporter; + constructor(aiKey: string) { + this._telemetryReporter = new TelemetryReporter(aiKey); + } + + get telemetryReporter(): TelemetryReporter { + return this._telemetryReporter; + } + + setSharedProperty(name: string, value: string): void { + this.sharedProperties[name] = value; + } + + postEvent(eventName: string, props: Map): void { + const eventProperties: TelemetryEventProperties = { ...this.sharedProperties, ...Object.fromEntries(props) }; + this._telemetryReporter.sendTelemetryEvent( + eventName, + eventProperties + ); + } + + sendLoginEvent(scopes: readonly string[]): void { + /* __GDPR__ + "login" : { + "owner": "TylerLeonhardt", + "comment": "Used to determine the usage of the Microsoft Auth Provider.", + "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } + } + */ + this._telemetryReporter.sendTelemetryEvent('login', { + // Get rid of guids from telemetry. + scopes: JSON.stringify(this._scrubGuids(scopes)), + }); + } + sendLoginFailedEvent(): void { + /* __GDPR__ + "loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } + */ + this._telemetryReporter.sendTelemetryEvent('loginFailed'); + } + sendLogoutEvent(): void { + /* __GDPR__ + "logout" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } + */ + this._telemetryReporter.sendTelemetryEvent('logout'); + } + sendLogoutFailedEvent(): void { + /* __GDPR__ + "logoutFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } + */ + this._telemetryReporter.sendTelemetryEvent('logoutFailed'); + } + /** + * Sends an event for an account type available at startup. + * @param scopes The scopes for the session + * @param accountType The account type for the session + * @todo Remove the scopes since we really don't care about them. + */ + sendAccountEvent(scopes: string[], accountType: MicrosoftAccountType): void { + /* __GDPR__ + "login" : { + "owner": "TylerLeonhardt", + "comment": "Used to determine the usage of the Microsoft Auth Provider.", + "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." }, + "accountType": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what account types are being used." } + } + */ + this._telemetryReporter.sendTelemetryEvent('account', { + // Get rid of guids from telemetry. + scopes: JSON.stringify(this._scrubGuids(scopes)), + accountType + }); + } + + protected _scrubGuids(scopes: readonly string[]): string[] { + return scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}')); + } +} + +export class MicrosoftSovereignCloudAuthenticationTelemetryReporter extends MicrosoftAuthenticationTelemetryReporter { + override sendLoginEvent(scopes: string[]): void { + /* __GDPR__ + "loginMicrosoftSovereignCloud" : { + "owner": "TylerLeonhardt", + "comment": "Used to determine the usage of the Microsoft Auth Provider.", + "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } + } + */ + this._telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloud', { + // Get rid of guids from telemetry. + scopes: JSON.stringify(this._scrubGuids(scopes)), + }); + } + override sendLoginFailedEvent(): void { + /* __GDPR__ + "loginMicrosoftSovereignCloudFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } + */ + this._telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloudFailed'); + } + override sendLogoutEvent(): void { + /* __GDPR__ + "logoutMicrosoftSovereignCloud" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } + */ + this._telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloud'); + } + override sendLogoutFailedEvent(): void { + /* __GDPR__ + "logoutMicrosoftSovereignCloudFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } + */ + this._telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloudFailed'); + } +} diff --git a/extensions/microsoft-authentication/src/common/test/loopbackClientAndOpener.test.ts b/extensions/microsoft-authentication/src/common/test/loopbackClientAndOpener.test.ts new file mode 100644 index 00000000000..5c55567d1d0 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/test/loopbackClientAndOpener.test.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { env, Uri } from 'vscode'; +import * as sinon from 'sinon'; +import { UriHandlerLoopbackClient } from '../loopbackClientAndOpener'; +import { UriEventHandler } from '../../UriEventHandler'; + +suite('UriHandlerLoopbackClient', () => { + const redirectUri = 'http://localhost'; + let uriHandler: UriEventHandler; + let client: UriHandlerLoopbackClient; + let envStub: sinon.SinonStubbedInstance; + let callbackUri: Uri; + + setup(async () => { + callbackUri = await env.asExternalUri(Uri.parse(`${env.uriScheme}://vscode.microsoft-authentication`)); + envStub = sinon.stub(env); + envStub.openExternal.resolves(true); + envStub.asExternalUri.callThrough(); + uriHandler = new UriEventHandler(); + client = new UriHandlerLoopbackClient(uriHandler, redirectUri); + }); + + teardown(() => { + sinon.restore(); + uriHandler.dispose(); + }); + + suite('openBrowser', () => { + test('should open browser with correct URL', async () => { + const testUrl = 'http://example.com?foo=5'; + + await client.openBrowser(testUrl); + + assert.ok(envStub.asExternalUri.calledOnce); + assert.ok(envStub.openExternal.calledOnce); + + const expectedUri = Uri.parse(testUrl + `&state=${encodeURI(callbackUri.toString(true))}`); + const value = envStub.openExternal.getCalls()[0].args[0]; + assert.strictEqual(value.toString(true), expectedUri.toString(true)); + }); + }); + + suite('getRedirectUri', () => { + test('should return the redirect URI', () => { + const result = client.getRedirectUri(); + assert.strictEqual(result, redirectUri); + }); + }); + + suite('listenForAuthCode', () => { + test('should return auth code from URL', async () => { + const code = '1234'; + const state = '5678'; + const testUrl = Uri.parse(`http://example.com?code=${code}&state=${state}`); + const promise = client.listenForAuthCode(); + uriHandler.handleUri(testUrl); + const result = await promise; + + assert.strictEqual(result.code, code); + assert.strictEqual(result.state, state); + }); + + test('should return auth error from URL', async () => { + const error = 'access_denied'; + const errorDescription = 'reason'; + const errorUri = 'uri'; + const testUrl = Uri.parse(`http://example.com?error=${error}&error_description=${errorDescription}&error_uri=${errorUri}`); + + const promise = client.listenForAuthCode(); + uriHandler.handleUri(testUrl); + const result = await promise; + + assert.strictEqual(result.error, 'access_denied'); + assert.strictEqual(result.error_description, 'reason'); + assert.strictEqual(result.error_uri, 'uri'); + }); + }); +}); diff --git a/extensions/microsoft-authentication/src/common/test/scopeData.test.ts b/extensions/microsoft-authentication/src/common/test/scopeData.test.ts new file mode 100644 index 00000000000..c0b578d4e80 --- /dev/null +++ b/extensions/microsoft-authentication/src/common/test/scopeData.test.ts @@ -0,0 +1,54 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { ScopeData } from '../scopeData'; + +suite('ScopeData', () => { + test('should include default scopes if not present', () => { + const scopeData = new ScopeData(['custom_scope']); + assert.deepStrictEqual(scopeData.allScopes, ['custom_scope', 'email', 'offline_access', 'openid', 'profile']); + }); + + test('should not duplicate default scopes if already present', () => { + const scopeData = new ScopeData(['openid', 'email', 'profile', 'offline_access']); + assert.deepStrictEqual(scopeData.allScopes, ['email', 'offline_access', 'openid', 'profile']); + }); + + test('should sort the scopes alphabetically', () => { + const scopeData = new ScopeData(['profile', 'email', 'openid', 'offline_access']); + assert.deepStrictEqual(scopeData.allScopes, ['email', 'offline_access', 'openid', 'profile']); + }); + + test('should create a space-separated string of all scopes', () => { + const scopeData = new ScopeData(['custom_scope']); + assert.strictEqual(scopeData.scopeStr, 'custom_scope email offline_access openid profile'); + }); + + test('should filter out internal VS Code scopes for scopesToSend', () => { + const scopeData = new ScopeData(['custom_scope', 'VSCODE_CLIENT_ID:some_id']); + assert.deepStrictEqual(scopeData.scopesToSend, ['custom_scope']); + }); + + test('should use the default client ID if no VSCODE_CLIENT_ID scope is present', () => { + const scopeData = new ScopeData(['custom_scope']); + assert.strictEqual(scopeData.clientId, 'aebc6443-996d-45c2-90f0-388ff96faa56'); + }); + + test('should use the VSCODE_CLIENT_ID scope if present', () => { + const scopeData = new ScopeData(['custom_scope', 'VSCODE_CLIENT_ID:some_id']); + assert.strictEqual(scopeData.clientId, 'some_id'); + }); + + test('should use the default tenant ID if no VSCODE_TENANT scope is present', () => { + const scopeData = new ScopeData(['custom_scope']); + assert.strictEqual(scopeData.tenant, 'organizations'); + }); + + test('should use the VSCODE_TENANT scope if present', () => { + const scopeData = new ScopeData(['custom_scope', 'VSCODE_TENANT:some_tenant']); + assert.strictEqual(scopeData.tenant, 'some_tenant'); + }); +}); diff --git a/extensions/microsoft-authentication/src/extension.ts b/extensions/microsoft-authentication/src/extension.ts index 87dc94e4c25..3f9b5d3a4d1 100644 --- a/extensions/microsoft-authentication/src/extension.ts +++ b/extensions/microsoft-authentication/src/extension.ts @@ -3,179 +3,83 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; -import { Environment, EnvironmentParameters } from '@azure/ms-rest-azure-env'; -import { AzureActiveDirectoryService, IStoredSession } from './AADHelper'; -import { BetterTokenStorage } from './betterSecretStorage'; -import { UriEventHandler } from './UriEventHandler'; -import TelemetryReporter from '@vscode/extension-telemetry'; - -async function initMicrosoftSovereignCloudAuthProvider(context: vscode.ExtensionContext, telemetryReporter: TelemetryReporter, uriHandler: UriEventHandler, tokenStorage: BetterTokenStorage): Promise { - const environment = vscode.workspace.getConfiguration('microsoft-sovereign-cloud').get('environment'); - let authProviderName: string | undefined; - if (!environment) { - return undefined; +import { commands, env, ExtensionContext, l10n, window, workspace } from 'vscode'; +import * as extensionV1 from './extensionV1'; +import * as extensionV2 from './extensionV2'; +import { createExperimentationService } from './common/experimentation'; +import { MicrosoftAuthenticationTelemetryReporter } from './common/telemetryReporter'; +import { IExperimentationService } from 'vscode-tas-client'; +import Logger from './logger'; + +function shouldUseMsal(expService: IExperimentationService): boolean { + // First check if there is a setting value to allow user to override the default + const inspect = workspace.getConfiguration('microsoft').inspect('useMsal'); + if (inspect?.workspaceFolderValue !== undefined) { + Logger.debug(`Acquired MSAL enablement value from 'workspaceFolderValue'. Value: ${inspect.workspaceFolderValue}`); + return inspect.workspaceFolderValue; } - - if (environment === 'custom') { - const customEnv = vscode.workspace.getConfiguration('microsoft-sovereign-cloud').get('customEnvironment'); - if (!customEnv) { - const res = await vscode.window.showErrorMessage(vscode.l10n.t('You must also specify a custom environment in order to use the custom environment auth provider.'), vscode.l10n.t('Open settings')); - if (res) { - await vscode.commands.executeCommand('workbench.action.openSettingsJson', 'microsoft-sovereign-cloud.customEnvironment'); - } - return undefined; - } - try { - Environment.add(customEnv); - } catch (e) { - const res = await vscode.window.showErrorMessage(vscode.l10n.t('Error validating custom environment setting: {0}', e.message), vscode.l10n.t('Open settings')); - if (res) { - await vscode.commands.executeCommand('workbench.action.openSettings', 'microsoft-sovereign-cloud.customEnvironment'); - } - return undefined; - } - authProviderName = customEnv.name; - } else { - authProviderName = environment; + if (inspect?.workspaceValue !== undefined) { + Logger.debug(`Acquired MSAL enablement value from 'workspaceValue'. Value: ${inspect.workspaceValue}`); + return inspect.workspaceValue; } - - const env = Environment.get(authProviderName); - if (!env) { - const res = await vscode.window.showErrorMessage(vscode.l10n.t('The environment `{0}` is not a valid environment.', authProviderName), vscode.l10n.t('Open settings')); - return undefined; + if (inspect?.globalValue !== undefined) { + Logger.debug(`Acquired MSAL enablement value from 'globalValue'. Value: ${inspect.globalValue}`); + return inspect.globalValue; } - const aadService = new AzureActiveDirectoryService( - vscode.window.createOutputChannel(vscode.l10n.t('Microsoft Sovereign Cloud Authentication'), { log: true }), - context, - uriHandler, - tokenStorage, - telemetryReporter, - env); - await aadService.initialize(); - - const disposable = vscode.authentication.registerAuthenticationProvider('microsoft-sovereign-cloud', authProviderName, { - onDidChangeSessions: aadService.onDidChangeSessions, - getSessions: (scopes: string[]) => aadService.getSessions(scopes), - createSession: async (scopes: string[]) => { - try { - /* __GDPR__ - "login" : { - "owner": "TylerLeonhardt", - "comment": "Used to determine the usage of the Microsoft Sovereign Cloud Auth Provider.", - "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } - } - */ - telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloud', { - // Get rid of guids from telemetry. - scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))), - }); - - return await aadService.createSession(scopes); - } catch (e) { - /* __GDPR__ - "loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } - */ - telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloudFailed'); - - throw e; - } - }, - removeSession: async (id: string) => { - try { - /* __GDPR__ - "logout" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } - */ - telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloud'); - - await aadService.removeSessionById(id); - } catch (e) { - /* __GDPR__ - "logoutFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } - */ - telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloudFailed'); - } - } - }, { supportsMultipleAccounts: true }); + // Then check if the experiment value + const expValue = expService.getTreatmentVariable('vscode', 'microsoft.useMsal'); + if (expValue !== undefined) { + Logger.debug(`Acquired MSAL enablement value from 'exp'. Value: ${expValue}`); + return expValue; + } - context.subscriptions.push(disposable); - return disposable; + Logger.debug('Acquired MSAL enablement value from default. Value: false'); + // If no setting or experiment value is found, default to false + return false; } +let useMsal: boolean | undefined; -export async function activate(context: vscode.ExtensionContext) { - const aiKey: string = context.extension.packageJSON.aiKey; - const telemetryReporter = new TelemetryReporter(aiKey); - - const uriHandler = new UriEventHandler(); - context.subscriptions.push(uriHandler); - context.subscriptions.push(vscode.window.registerUriHandler(uriHandler)); - const betterSecretStorage = new BetterTokenStorage('microsoft.login.keylist', context); - - const loginService = new AzureActiveDirectoryService( - vscode.window.createOutputChannel(vscode.l10n.t('Microsoft Authentication'), { log: true }), +export async function activate(context: ExtensionContext) { + const mainTelemetryReporter = new MicrosoftAuthenticationTelemetryReporter(context.extension.packageJSON.aiKey); + const expService = await createExperimentationService( context, - uriHandler, - betterSecretStorage, - telemetryReporter, - Environment.AzureCloud); - await loginService.initialize(); - - context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', { - onDidChangeSessions: loginService.onDidChangeSessions, - getSessions: (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => loginService.getSessions(scopes, options?.account), - createSession: async (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => { - try { - /* __GDPR__ - "login" : { - "owner": "TylerLeonhardt", - "comment": "Used to determine the usage of the Microsoft Auth Provider.", - "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } - } - */ - telemetryReporter.sendTelemetryEvent('login', { - // Get rid of guids from telemetry. - scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))), - }); - - return await loginService.createSession(scopes, options?.account); - } catch (e) { - /* __GDPR__ - "loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } - */ - telemetryReporter.sendTelemetryEvent('loginFailed'); - - throw e; - } - }, - removeSession: async (id: string) => { - try { - /* __GDPR__ - "logout" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } - */ - telemetryReporter.sendTelemetryEvent('logout'); - - await loginService.removeSessionById(id); - } catch (e) { - /* __GDPR__ - "logoutFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } - */ - telemetryReporter.sendTelemetryEvent('logoutFailed'); - } + mainTelemetryReporter, + env.uriScheme !== 'vscode', // isPreRelease + ); + useMsal = shouldUseMsal(expService); + + context.subscriptions.push(workspace.onDidChangeConfiguration(async e => { + if (!e.affectsConfiguration('microsoft.useMsal') || useMsal === shouldUseMsal(expService)) { + return; } - }, { supportsMultipleAccounts: true })); - - let microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, telemetryReporter, uriHandler, betterSecretStorage); - context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async e => { - if (e.affectsConfiguration('microsoft-sovereign-cloud')) { - microsoftSovereignCloudAuthProviderDisposable?.dispose(); - microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, telemetryReporter, uriHandler, betterSecretStorage); + const reload = l10n.t('Reload'); + const result = await window.showInformationMessage( + 'Reload required', + { + modal: true, + detail: l10n.t('Microsoft Account configuration has been changed.'), + }, + reload + ); + + if (result === reload) { + commands.executeCommand('workbench.action.reloadWindow'); } })); - - return; + // Only activate the new extension if we are not running in a browser environment + if (useMsal && typeof navigator === 'undefined') { + await extensionV2.activate(context, mainTelemetryReporter); + } else { + await extensionV1.activate(context, mainTelemetryReporter.telemetryReporter); + } } -// this method is called when your extension is deactivated -export function deactivate() { } +export function deactivate() { + if (useMsal) { + extensionV2.deactivate(); + } else { + extensionV1.deactivate(); + } +} diff --git a/extensions/microsoft-authentication/src/extensionV1.ts b/extensions/microsoft-authentication/src/extensionV1.ts new file mode 100644 index 00000000000..f785adad85c --- /dev/null +++ b/extensions/microsoft-authentication/src/extensionV1.ts @@ -0,0 +1,178 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Environment, EnvironmentParameters } from '@azure/ms-rest-azure-env'; +import { AzureActiveDirectoryService, IStoredSession } from './AADHelper'; +import { BetterTokenStorage } from './betterSecretStorage'; +import { UriEventHandler } from './UriEventHandler'; +import TelemetryReporter from '@vscode/extension-telemetry'; +import Logger from './logger'; + +async function initMicrosoftSovereignCloudAuthProvider(context: vscode.ExtensionContext, telemetryReporter: TelemetryReporter, uriHandler: UriEventHandler, tokenStorage: BetterTokenStorage): Promise { + const environment = vscode.workspace.getConfiguration('microsoft-sovereign-cloud').get('environment'); + let authProviderName: string | undefined; + if (!environment) { + return undefined; + } + + if (environment === 'custom') { + const customEnv = vscode.workspace.getConfiguration('microsoft-sovereign-cloud').get('customEnvironment'); + if (!customEnv) { + const res = await vscode.window.showErrorMessage(vscode.l10n.t('You must also specify a custom environment in order to use the custom environment auth provider.'), vscode.l10n.t('Open settings')); + if (res) { + await vscode.commands.executeCommand('workbench.action.openSettingsJson', 'microsoft-sovereign-cloud.customEnvironment'); + } + return undefined; + } + try { + Environment.add(customEnv); + } catch (e) { + const res = await vscode.window.showErrorMessage(vscode.l10n.t('Error validating custom environment setting: {0}', e.message), vscode.l10n.t('Open settings')); + if (res) { + await vscode.commands.executeCommand('workbench.action.openSettings', 'microsoft-sovereign-cloud.customEnvironment'); + } + return undefined; + } + authProviderName = customEnv.name; + } else { + authProviderName = environment; + } + + const env = Environment.get(authProviderName); + if (!env) { + const res = await vscode.window.showErrorMessage(vscode.l10n.t('The environment `{0}` is not a valid environment.', authProviderName), vscode.l10n.t('Open settings')); + return undefined; + } + + const aadService = new AzureActiveDirectoryService( + vscode.window.createOutputChannel(vscode.l10n.t('Microsoft Sovereign Cloud Authentication'), { log: true }), + context, + uriHandler, + tokenStorage, + telemetryReporter, + env); + await aadService.initialize(); + + const disposable = vscode.authentication.registerAuthenticationProvider('microsoft-sovereign-cloud', authProviderName, { + onDidChangeSessions: aadService.onDidChangeSessions, + getSessions: (scopes: string[]) => aadService.getSessions(scopes), + createSession: async (scopes: string[]) => { + try { + /* __GDPR__ + "login" : { + "owner": "TylerLeonhardt", + "comment": "Used to determine the usage of the Microsoft Sovereign Cloud Auth Provider.", + "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } + } + */ + telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloud', { + // Get rid of guids from telemetry. + scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))), + }); + + return await aadService.createSession(scopes); + } catch (e) { + /* __GDPR__ + "loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } + */ + telemetryReporter.sendTelemetryEvent('loginMicrosoftSovereignCloudFailed'); + + throw e; + } + }, + removeSession: async (id: string) => { + try { + /* __GDPR__ + "logout" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } + */ + telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloud'); + + await aadService.removeSessionById(id); + } catch (e) { + /* __GDPR__ + "logoutFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } + */ + telemetryReporter.sendTelemetryEvent('logoutMicrosoftSovereignCloudFailed'); + } + } + }, { supportsMultipleAccounts: true }); + + context.subscriptions.push(disposable); + return disposable; +} + +export async function activate(context: vscode.ExtensionContext, telemetryReporter: TelemetryReporter) { + const uriHandler = new UriEventHandler(); + context.subscriptions.push(uriHandler); + const betterSecretStorage = new BetterTokenStorage('microsoft.login.keylist', context); + + const loginService = new AzureActiveDirectoryService( + Logger, + context, + uriHandler, + betterSecretStorage, + telemetryReporter, + Environment.AzureCloud); + await loginService.initialize(); + + context.subscriptions.push(vscode.authentication.registerAuthenticationProvider('microsoft', 'Microsoft', { + onDidChangeSessions: loginService.onDidChangeSessions, + getSessions: (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => loginService.getSessions(scopes, options?.account), + createSession: async (scopes: string[], options?: vscode.AuthenticationProviderSessionOptions) => { + try { + /* __GDPR__ + "login" : { + "owner": "TylerLeonhardt", + "comment": "Used to determine the usage of the Microsoft Auth Provider.", + "scopes": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight", "comment": "Used to determine what scope combinations are being requested." } + } + */ + telemetryReporter.sendTelemetryEvent('login', { + // Get rid of guids from telemetry. + scopes: JSON.stringify(scopes.map(s => s.replace(/[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}/i, '{guid}'))), + }); + + return await loginService.createSession(scopes, options?.account); + } catch (e) { + /* __GDPR__ + "loginFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users run into issues with the login flow." } + */ + telemetryReporter.sendTelemetryEvent('loginFailed'); + + throw e; + } + }, + removeSession: async (id: string) => { + try { + /* __GDPR__ + "logout" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often users log out." } + */ + telemetryReporter.sendTelemetryEvent('logout'); + + await loginService.removeSessionById(id); + } catch (e) { + /* __GDPR__ + "logoutFailed" : { "owner": "TylerLeonhardt", "comment": "Used to determine how often fail to log out." } + */ + telemetryReporter.sendTelemetryEvent('logoutFailed'); + } + } + }, { supportsMultipleAccounts: true })); + + let microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, telemetryReporter, uriHandler, betterSecretStorage); + + context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async e => { + if (e.affectsConfiguration('microsoft-sovereign-cloud')) { + microsoftSovereignCloudAuthProviderDisposable?.dispose(); + microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, telemetryReporter, uriHandler, betterSecretStorage); + } + })); + + return; +} + +// this method is called when your extension is deactivated +export function deactivate() { } diff --git a/extensions/microsoft-authentication/src/extensionV2.ts b/extensions/microsoft-authentication/src/extensionV2.ts new file mode 100644 index 00000000000..9610af37977 --- /dev/null +++ b/extensions/microsoft-authentication/src/extensionV2.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Environment, EnvironmentParameters } from '@azure/ms-rest-azure-env'; +import Logger from './logger'; +import { MsalAuthProvider } from './node/authProvider'; +import { UriEventHandler } from './UriEventHandler'; +import { authentication, commands, ExtensionContext, l10n, window, workspace, Disposable } from 'vscode'; +import { MicrosoftAuthenticationTelemetryReporter, MicrosoftSovereignCloudAuthenticationTelemetryReporter } from './common/telemetryReporter'; + +async function initMicrosoftSovereignCloudAuthProvider( + context: ExtensionContext, + uriHandler: UriEventHandler +): Promise { + const environment = workspace.getConfiguration('microsoft-sovereign-cloud').get('environment'); + let authProviderName: string | undefined; + if (!environment) { + return undefined; + } + + if (environment === 'custom') { + const customEnv = workspace.getConfiguration('microsoft-sovereign-cloud').get('customEnvironment'); + if (!customEnv) { + const res = await window.showErrorMessage(l10n.t('You must also specify a custom environment in order to use the custom environment auth provider.'), l10n.t('Open settings')); + if (res) { + await commands.executeCommand('workbench.action.openSettingsJson', 'microsoft-sovereign-cloud.customEnvironment'); + } + return undefined; + } + try { + Environment.add(customEnv); + } catch (e) { + const res = await window.showErrorMessage(l10n.t('Error validating custom environment setting: {0}', e.message), l10n.t('Open settings')); + if (res) { + await commands.executeCommand('workbench.action.openSettings', 'microsoft-sovereign-cloud.customEnvironment'); + } + return undefined; + } + authProviderName = customEnv.name; + } else { + authProviderName = environment; + } + + const env = Environment.get(authProviderName); + if (!env) { + await window.showErrorMessage(l10n.t('The environment `{0}` is not a valid environment.', authProviderName), l10n.t('Open settings')); + return undefined; + } + + const authProvider = new MsalAuthProvider( + context, + new MicrosoftSovereignCloudAuthenticationTelemetryReporter(context.extension.packageJSON.aiKey), + window.createOutputChannel(l10n.t('Microsoft Sovereign Cloud Authentication'), { log: true }), + uriHandler, + env + ); + await authProvider.initialize(); + const disposable = authentication.registerAuthenticationProvider( + 'microsoft-sovereign-cloud', + authProviderName, + authProvider, + { supportsMultipleAccounts: true } + ); + context.subscriptions.push(disposable); + return disposable; +} + +export async function activate(context: ExtensionContext, mainTelemetryReporter: MicrosoftAuthenticationTelemetryReporter) { + const uriHandler = new UriEventHandler(); + context.subscriptions.push(uriHandler); + const authProvider = new MsalAuthProvider( + context, + mainTelemetryReporter, + Logger, + uriHandler + ); + await authProvider.initialize(); + context.subscriptions.push(authentication.registerAuthenticationProvider( + 'microsoft', + 'Microsoft', + authProvider, + { supportsMultipleAccounts: true } + )); + + let microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, uriHandler); + + context.subscriptions.push(workspace.onDidChangeConfiguration(async e => { + if (e.affectsConfiguration('microsoft-sovereign-cloud')) { + microsoftSovereignCloudAuthProviderDisposable?.dispose(); + microsoftSovereignCloudAuthProviderDisposable = await initMicrosoftSovereignCloudAuthProvider(context, uriHandler); + } + })); +} + +export function deactivate() { } diff --git a/extensions/microsoft-authentication/src/node/authProvider.ts b/extensions/microsoft-authentication/src/node/authProvider.ts new file mode 100644 index 00000000000..3925f6f58cf --- /dev/null +++ b/extensions/microsoft-authentication/src/node/authProvider.ts @@ -0,0 +1,242 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { AccountInfo, AuthenticationResult, ServerError } from '@azure/msal-node'; +import { AuthenticationGetSessionOptions, AuthenticationProvider, AuthenticationProviderAuthenticationSessionsChangeEvent, AuthenticationSession, AuthenticationSessionAccountInformation, CancellationError, env, EventEmitter, ExtensionContext, l10n, LogOutputChannel, Memento, SecretStorage, Uri, window } from 'vscode'; +import { Environment } from '@azure/ms-rest-azure-env'; +import { CachedPublicClientApplicationManager } from './publicClientCache'; +import { UriHandlerLoopbackClient } from '../common/loopbackClientAndOpener'; +import { UriEventHandler } from '../UriEventHandler'; +import { ICachedPublicClientApplication } from '../common/publicClientCache'; +import { MicrosoftAccountType, MicrosoftAuthenticationTelemetryReporter } from '../common/telemetryReporter'; +import { loopbackTemplate } from './loopbackTemplate'; +import { ScopeData } from '../common/scopeData'; + +const redirectUri = 'https://vscode.dev/redirect'; +const MSA_TID = '9188040d-6c67-4c5b-b112-36a304b66dad'; +const MSA_PASSTHRU_TID = 'f8cdef31-a31e-4b4a-93e4-5f571e91255a'; + +export class MsalAuthProvider implements AuthenticationProvider { + + private readonly _disposables: { dispose(): void }[]; + private readonly _publicClientManager: CachedPublicClientApplicationManager; + + /** + * Event to signal a change in authentication sessions for this provider. + */ + private readonly _onDidChangeSessionsEmitter = new EventEmitter(); + + /** + * Event to signal a change in authentication sessions for this provider. + * + * NOTE: This event is handled differently in the Microsoft auth provider than "typical" auth providers. Normally, + * this event would fire when the provider's sessions change... which are tied to a specific list of scopes. However, + * since Microsoft identity doesn't care too much about scopes (you can mint a new token from an existing token), + * we just fire this event whenever the account list changes... so essentially there is one session per account. + * + * This is not quite how the API should be used... but this event really is just for signaling that the account list + * has changed. + */ + onDidChangeSessions = this._onDidChangeSessionsEmitter.event; + + constructor( + context: ExtensionContext, + private readonly _telemetryReporter: MicrosoftAuthenticationTelemetryReporter, + private readonly _logger: LogOutputChannel, + private readonly _uriHandler: UriEventHandler, + private readonly _env: Environment = Environment.AzureCloud + ) { + this._disposables = context.subscriptions; + this._publicClientManager = new CachedPublicClientApplicationManager( + context.globalState, + context.secrets, + this._logger, + (e) => this._handleAccountChange(e) + ); + this._disposables.push(this._publicClientManager); + this._disposables.push(this._onDidChangeSessionsEmitter); + + } + + async initialize(): Promise { + await this._publicClientManager.initialize(); + + // Send telemetry for existing accounts + for (const cachedPca of this._publicClientManager.getAll()) { + for (const account of cachedPca.accounts) { + if (!account.idTokenClaims?.tid) { + continue; + } + const tid = account.idTokenClaims.tid; + const type = tid === MSA_TID || tid === MSA_PASSTHRU_TID ? MicrosoftAccountType.MSA : MicrosoftAccountType.AAD; + this._telemetryReporter.sendAccountEvent([], type); + } + } + } + + /** + * See {@link onDidChangeSessions} for more information on how this is used. + * @param param0 Event that contains the added and removed accounts + */ + private _handleAccountChange({ added, deleted }: { added: AccountInfo[]; deleted: AccountInfo[] }) { + const process = (a: AccountInfo) => ({ + // This shouldn't be needed + accessToken: '1234', + id: a.homeAccountId, + scopes: [], + account: { + id: a.homeAccountId, + label: a.username + }, + idToken: a.idToken, + }); + this._onDidChangeSessionsEmitter.fire({ added: added.map(process), changed: [], removed: deleted.map(process) }); + } + + //#region AuthenticationProvider methods + + async getSessions(scopes: string[] | undefined, options?: AuthenticationGetSessionOptions): Promise { + const scopeData = new ScopeData(scopes); + this._logger.info('[getSessions]', scopes ? scopeData.scopeStr : 'all', 'starting'); + if (!scopes) { + // Do NOT use `scopes` beyond this place in the code. Use `scopeData` instead. + + const allSessions: AuthenticationSession[] = []; + for (const cachedPca of this._publicClientManager.getAll()) { + const sessions = await this.getAllSessionsForPca(cachedPca, scopeData.originalScopes, scopeData.scopesToSend, options?.account); + allSessions.push(...sessions); + } + return allSessions; + } + + const cachedPca = await this.getOrCreatePublicClientApplication(scopeData.clientId, scopeData.tenant); + const sessions = await this.getAllSessionsForPca(cachedPca, scopeData.originalScopes, scopeData.scopesToSend, options?.account); + this._logger.info(`[getSessions] returned ${sessions.length} sessions`); + return sessions; + + } + + async createSession(scopes: readonly string[]): Promise { + const scopeData = new ScopeData(scopes); + // Do NOT use `scopes` beyond this place in the code. Use `scopeData` instead. + + this._logger.info('[createSession]', scopeData.scopeStr, 'starting'); + const cachedPca = await this.getOrCreatePublicClientApplication(scopeData.clientId, scopeData.tenant); + let result: AuthenticationResult; + try { + result = await cachedPca.acquireTokenInteractive({ + openBrowser: async (url: string) => { await env.openExternal(Uri.parse(url)); }, + scopes: scopeData.scopesToSend, + // The logic for rendering one or the other of these templates is in the + // template itself, so we pass the same one for both. + successTemplate: loopbackTemplate, + errorTemplate: loopbackTemplate + }); + } catch (e) { + if (e instanceof CancellationError) { + const yes = l10n.t('Yes'); + const result = await window.showErrorMessage( + l10n.t('Having trouble logging in?'), + { + modal: true, + detail: l10n.t('Would you like to try a different way to sign in to your Microsoft account? ({0})', 'protocol handler') + }, + yes + ); + if (!result) { + this._telemetryReporter.sendLoginFailedEvent(); + throw e; + } + } + // This error comes from the backend and is likely not due to the user's machine + // failing to open a port or something local that would require us to try the + // URL handler loopback client. + if (e instanceof ServerError) { + this._telemetryReporter.sendLoginFailedEvent(); + throw e; + } + const loopbackClient = new UriHandlerLoopbackClient(this._uriHandler, redirectUri); + try { + result = await cachedPca.acquireTokenInteractive({ + openBrowser: (url: string) => loopbackClient.openBrowser(url), + scopes: scopeData.scopesToSend, + loopbackClient + }); + } catch (e) { + this._telemetryReporter.sendLoginFailedEvent(); + throw e; + } + } + + const session = this.toAuthenticationSession(result, scopeData.originalScopes); + this._telemetryReporter.sendLoginEvent(session.scopes); + this._logger.info('[createSession]', scopeData.scopeStr, 'returned session'); + this._onDidChangeSessionsEmitter.fire({ added: [session], changed: [], removed: [] }); + return session; + } + + async removeSession(sessionId: string): Promise { + this._logger.info('[removeSession]', sessionId, 'starting'); + for (const cachedPca of this._publicClientManager.getAll()) { + const accounts = cachedPca.accounts; + for (const account of accounts) { + if (account.homeAccountId === sessionId) { + this._telemetryReporter.sendLogoutEvent(); + try { + await cachedPca.removeAccount(account); + } catch (e) { + this._telemetryReporter.sendLogoutFailedEvent(); + throw e; + } + this._logger.info('[removeSession]', sessionId, 'removed session'); + return; + } + } + } + this._logger.info('[removeSession]', sessionId, 'session not found'); + } + + //#endregion + + private async getOrCreatePublicClientApplication(clientId: string, tenant: string): Promise { + const authority = new URL(tenant, this._env.activeDirectoryEndpointUrl).toString(); + return await this._publicClientManager.getOrCreate(clientId, authority); + } + + private async getAllSessionsForPca( + cachedPca: ICachedPublicClientApplication, + originalScopes: readonly string[], + scopesToSend: string[], + accountFilter?: AuthenticationSessionAccountInformation + ): Promise { + const accounts = accountFilter + ? cachedPca.accounts.filter(a => a.homeAccountId === accountFilter.id) + : cachedPca.accounts; + const sessions: AuthenticationSession[] = []; + for (const account of accounts) { + try { + const result = await cachedPca.acquireTokenSilent({ account, scopes: scopesToSend, redirectUri }); + sessions.push(this.toAuthenticationSession(result, originalScopes)); + } catch (e) { + // If we can't get a token silently, the account is probably in a bad state so we should skip it + // MSAL will log this already, so we don't need to log it again + continue; + } + } + return sessions; + } + + private toAuthenticationSession(result: AuthenticationResult, scopes: readonly string[]): AuthenticationSession & { idToken: string } { + return { + accessToken: result.accessToken, + idToken: result.idToken, + id: result.account?.homeAccountId ?? result.uniqueId, + account: { + id: result.account?.homeAccountId ?? result.uniqueId, + label: result.account?.username ?? 'Unknown', + }, + scopes + }; + } +} diff --git a/extensions/microsoft-authentication/src/node/loopbackTemplate.ts b/extensions/microsoft-authentication/src/node/loopbackTemplate.ts new file mode 100644 index 00000000000..60d3cd4d9cc --- /dev/null +++ b/extensions/microsoft-authentication/src/node/loopbackTemplate.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +export const loopbackTemplate = ` + + + + + + Microsoft Account - Sign In + + + + + + + Visual Studio Code + +
+
+ You are signed in now and can close this page. +
+
+ An error occurred while signing in: +
+
+
+ + + + +`; diff --git a/extensions/microsoft-authentication/src/node/publicClientCache.ts b/extensions/microsoft-authentication/src/node/publicClientCache.ts new file mode 100644 index 00000000000..34bf2c3c73b --- /dev/null +++ b/extensions/microsoft-authentication/src/node/publicClientCache.ts @@ -0,0 +1,252 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { AccountInfo, AuthenticationResult, Configuration, InteractiveRequest, PublicClientApplication, SilentFlowRequest } from '@azure/msal-node'; +import { SecretStorageCachePlugin } from '../common/cachePlugin'; +import { SecretStorage, LogOutputChannel, Disposable, SecretStorageChangeEvent, EventEmitter, Memento, window, ProgressLocation, l10n } from 'vscode'; +import { MsalLoggerOptions } from '../common/loggerOptions'; +import { ICachedPublicClientApplication, ICachedPublicClientApplicationManager } from '../common/publicClientCache'; +import { raceCancellationAndTimeoutError } from '../common/async'; + +export interface IPublicClientApplicationInfo { + clientId: string; + authority: string; +} + +const _keyPrefix = 'pca:'; + +export class CachedPublicClientApplicationManager implements ICachedPublicClientApplicationManager { + // The key is the clientId and authority stringified + private readonly _pcas = new Map(); + + private _initialized = false; + private _disposable: Disposable; + + constructor( + private readonly _globalMemento: Memento, + private readonly _secretStorage: SecretStorage, + private readonly _logger: LogOutputChannel, + private readonly _accountChangeHandler: (e: { added: AccountInfo[]; deleted: AccountInfo[] }) => void + ) { + this._disposable = _secretStorage.onDidChange(e => this._handleSecretStorageChange(e)); + } + + async initialize() { + this._logger.debug('[initialize] Initializing PublicClientApplicationManager'); + const keys = await this._secretStorage.get('publicClientApplications'); + if (!keys) { + this._initialized = true; + return; + } + + const promises = new Array>(); + try { + for (const key of JSON.parse(keys) as string[]) { + try { + const { clientId, authority } = JSON.parse(key) as IPublicClientApplicationInfo; + // Load the PCA in memory + promises.push(this.getOrCreate(clientId, authority)); + } catch (e) { + // ignore + } + } + } catch (e) { + // data is corrupted + this._logger.error('[initialize] Error initializing PublicClientApplicationManager:', e); + await this._secretStorage.delete('publicClientApplications'); + } + + // TODO: should we do anything for when this fails? + await Promise.allSettled(promises); + this._logger.debug('[initialize] PublicClientApplicationManager initialized'); + this._initialized = true; + } + + dispose() { + this._disposable.dispose(); + Disposable.from(...this._pcas.values()).dispose(); + } + + async getOrCreate(clientId: string, authority: string): Promise { + if (!this._initialized) { + throw new Error('PublicClientApplicationManager not initialized'); + } + + // Use the clientId and authority as the key + const pcasKey = JSON.stringify({ clientId, authority }); + let pca = this._pcas.get(pcasKey); + if (pca) { + this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PublicClientApplicationManager cache hit`); + return pca; + } + + this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PublicClientApplicationManager cache miss, creating new PCA...`); + pca = new CachedPublicClientApplication(clientId, authority, this._globalMemento, this._secretStorage, this._accountChangeHandler, this._logger); + this._pcas.set(pcasKey, pca); + await pca.initialize(); + await this._storePublicClientApplications(); + this._logger.debug(`[getOrCreate] [${clientId}] [${authority}] PublicClientApplicationManager PCA created`); + return pca; + } + + getAll(): ICachedPublicClientApplication[] { + if (!this._initialized) { + throw new Error('PublicClientApplicationManager not initialized'); + } + return Array.from(this._pcas.values()); + } + + private async _handleSecretStorageChange(e: SecretStorageChangeEvent) { + if (!e.key.startsWith(_keyPrefix)) { + return; + } + + this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager secret storage change: ${e.key}`); + const result = await this._secretStorage.get(e.key); + const pcasKey = e.key.split(_keyPrefix)[1]; + + // If the cache was deleted, or the PCA has zero accounts left, remove the PCA + if (!result || this._pcas.get(pcasKey)?.accounts.length === 0) { + this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager removing PCA: ${pcasKey}`); + this._pcas.delete(pcasKey); + await this._storePublicClientApplications(); + this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager PCA removed: ${pcasKey}`); + return; + } + + // Load the PCA in memory if it's not already loaded + const { clientId, authority } = JSON.parse(pcasKey) as IPublicClientApplicationInfo; + this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager loading PCA: ${pcasKey}`); + await this.getOrCreate(clientId, authority); + this._logger.debug(`[handleSecretStorageChange] PublicClientApplicationManager PCA loaded: ${pcasKey}`); + } + + private async _storePublicClientApplications() { + await this._secretStorage.store( + 'publicClientApplications', + JSON.stringify(Array.from(this._pcas.keys())) + ); + } +} + +class CachedPublicClientApplication implements ICachedPublicClientApplication { + private _pca: PublicClientApplication; + + private _accounts: AccountInfo[] = []; + private readonly _disposable: Disposable; + + private readonly _loggerOptions = new MsalLoggerOptions(this._logger); + private readonly _secretStorageCachePlugin = new SecretStorageCachePlugin( + this._secretStorage, + // Include the prefix in the key so we can easily identify it later + `${_keyPrefix}${JSON.stringify({ clientId: this._clientId, authority: this._authority })}` + ); + private readonly _config: Configuration = { + auth: { clientId: this._clientId, authority: this._authority }, + system: { + loggerOptions: { + correlationId: `${this._clientId}] [${this._authority}`, + loggerCallback: (level, message, containsPii) => this._loggerOptions.loggerCallback(level, message, containsPii), + } + }, + cache: { + cachePlugin: this._secretStorageCachePlugin + } + }; + + /** + * We keep track of the last time an account was removed so we can recreate the PCA if we detect that an account was removed. + * This is due to MSAL-node not providing a way to detect when an account is removed from the cache. An internal issue has been + * filed to track this. If MSAL-node ever provides a way to detect this or handle this better in the Persistant Cache Plugin, + * we can remove this logic. + */ + private _lastCreated: Date; + + constructor( + private readonly _clientId: string, + private readonly _authority: string, + private readonly _globalMemento: Memento, + private readonly _secretStorage: SecretStorage, + private readonly _accountChangeHandler: (e: { added: AccountInfo[]; changed: AccountInfo[]; deleted: AccountInfo[] }) => void, + private readonly _logger: LogOutputChannel + ) { + this._pca = new PublicClientApplication(this._config); + this._lastCreated = new Date(); + this._disposable = this._registerOnSecretStorageChanged(); + } + + get accounts(): AccountInfo[] { return this._accounts; } + get clientId(): string { return this._clientId; } + get authority(): string { return this._authority; } + + initialize(): Promise { + return this._update(); + } + + dispose(): void { + this._disposable.dispose(); + } + + async acquireTokenSilent(request: SilentFlowRequest): Promise { + this._logger.debug(`[acquireTokenSilent] [${this._clientId}] [${this._authority}] [${request.scopes.join(' ')}]`); + const result = await this._pca.acquireTokenSilent(request); + if (result.account && !result.fromCache) { + this._accountChangeHandler({ added: [], changed: [result.account], deleted: [] }); + } + return result; + } + + async acquireTokenInteractive(request: InteractiveRequest): Promise { + this._logger.debug(`[acquireTokenInteractive] [${this._clientId}] [${this._authority}] [${request.scopes?.join(' ')}] loopbackClientOverride: ${request.loopbackClient ? 'true' : 'false'}`); + return await window.withProgress( + { + location: ProgressLocation.Notification, + cancellable: true, + title: l10n.t('Signing in to Microsoft...') + }, + (_process, token) => raceCancellationAndTimeoutError( + this._pca.acquireTokenInteractive(request), + token, + 1000 * 60 * 5 + ), // 5 minutes + ); + } + + removeAccount(account: AccountInfo): Promise { + this._globalMemento.update(`lastRemoval:${this._clientId}:${this._authority}`, new Date()); + return this._pca.getTokenCache().removeAccount(account); + } + + private _registerOnSecretStorageChanged() { + return this._secretStorageCachePlugin.onDidChange(() => this._update()); + } + + private async _update() { + const before = this._accounts; + this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update before: ${before.length}`); + // Dates are stored as strings in the memento + const lastRemovalDate = this._globalMemento.get(`lastRemoval:${this._clientId}:${this._authority}`); + if (lastRemovalDate && this._lastCreated && Date.parse(lastRemovalDate) > this._lastCreated.getTime()) { + this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication removal detected... recreating PCA...`); + this._pca = new PublicClientApplication(this._config); + this._lastCreated = new Date(); + } + + const after = await this._pca.getAllAccounts(); + this._accounts = after; + this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update after: ${after.length}`); + + const beforeSet = new Set(before.map(b => b.homeAccountId)); + const afterSet = new Set(after.map(a => a.homeAccountId)); + + const added = after.filter(a => !beforeSet.has(a.homeAccountId)); + const deleted = before.filter(b => !afterSet.has(b.homeAccountId)); + if (added.length > 0 || deleted.length > 0) { + this._accountChangeHandler({ added, changed: [], deleted }); + this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication accounts changed. added: ${added.length}, deleted: ${deleted.length}`); + } + this._logger.debug(`[update] [${this._clientId}] [${this._authority}] CachedPublicClientApplication update complete`); + } +} diff --git a/extensions/microsoft-authentication/tsconfig.json b/extensions/microsoft-authentication/tsconfig.json index cad76d078bd..4b9d06d1847 100644 --- a/extensions/microsoft-authentication/tsconfig.json +++ b/extensions/microsoft-authentication/tsconfig.json @@ -22,7 +22,6 @@ "include": [ "src/**/*", "../../src/vscode-dts/vscode.d.ts", - "../../src/vscode-dts/vscode.proposed.idToken.d.ts", - "../../src/vscode-dts/vscode.proposed.authGetSessions.d.ts" + "../../src/vscode-dts/vscode.proposed.idToken.d.ts" ] } diff --git a/extensions/microsoft-authentication/yarn.lock b/extensions/microsoft-authentication/yarn.lock index 703d54dd626..d0d70647b75 100644 --- a/extensions/microsoft-authentication/yarn.lock +++ b/extensions/microsoft-authentication/yarn.lock @@ -7,6 +7,20 @@ resolved "https://registry.yarnpkg.com/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz#45809f89763a480924e21d3c620cd40866771625" integrity sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw== +"@azure/msal-common@14.14.1": + version "14.14.1" + resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.14.1.tgz#62e4569518d2c52e7de1f460d40ab919ca66b99b" + integrity sha512-2Q3tqNz/PZLfSr8BvcHZVpRRfSn4MjGSqjj9J+HlBsmbf1Uu4P0WeXnemjTJwwx9KrmplsrN3UkZ/LPOR720rw== + +"@azure/msal-node@^2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.13.0.tgz#007ffffa84e4f91f00f816b980740837ce6626fe" + integrity sha512-DhP97ycs7qlCVzzzWGzJiwAFyFj5okno74E4FUZ61oCLfKh4IxA1kxirqzrWuYZWpBe9HVPL6GA4NvmlEOBN5Q== + dependencies: + "@azure/msal-common" "14.14.1" + jsonwebtoken "^9.0.0" + uuid "^8.3.0" + "@microsoft/1ds-core-js@4.0.3", "@microsoft/1ds-core-js@^4.0.3": version "4.0.3" resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-4.0.3.tgz#c8a92c623745a9595e06558a866658480c33bdf9" @@ -153,6 +167,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -165,6 +184,13 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + form-data@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" @@ -174,6 +200,74 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +jsonwebtoken@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + mime-db@1.44.0: version "1.44.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" @@ -186,7 +280,39 @@ mime-types@^2.1.12: dependencies: mime-db "1.44.0" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +safe-buffer@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +tas-client@0.2.33: + version "0.2.33" + resolved "https://registry.yarnpkg.com/tas-client/-/tas-client-0.2.33.tgz#451bf114a8a64748030ce4068ab7d079958402e6" + integrity sha512-V+uqV66BOQnWxvI6HjDnE4VkInmYZUQ4dgB7gzaDyFyFSK1i1nF/j7DpS9UbQAgV9NaF1XpcyuavnM1qOeiEIg== + undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vscode-tas-client@^0.1.84: + version "0.1.84" + resolved "https://registry.yarnpkg.com/vscode-tas-client/-/vscode-tas-client-0.1.84.tgz#906bdcfd8c9e1dc04321d6bc0335184f9119968e" + integrity sha512-rUTrUopV+70hvx1hW5ebdw1nd6djxubkLvVxjGdyD/r5v/wcVF41LIfiAtbm5qLZDtQdsMH1IaCuDoluoIa88w== + dependencies: + tas-client "0.2.33" diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 545ce102ab5..1deb5d23459 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -35,6 +35,14 @@ "@types/node": "20.x", "@types/which": "^3.0.0" }, + "overrides": { + "micromatch": "^4.0.6", + "braces": "^3.0.3" + }, + "resolutions": { + "micromatch": "^4.0.6", + "braces": "^3.0.3" + }, "main": "./out/npmMain", "browser": "./dist/browser/npmBrowserMain", "activationEvents": [ diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index a2f4fabcfe3..999f39664f1 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -293,7 +293,13 @@ export class PackageJSONContribution implements IJSONContribution { // COREPACK_ENABLE_PROJECT_SPEC makes the npm view command succeed // even if packageManager specified a package manager other than npm. const env = { ...process.env, COREPACK_ENABLE_AUTO_PIN: '0', COREPACK_ENABLE_PROJECT_SPEC: '0' }; - cp.execFile(npmCommandPath, args, { cwd, env }, (error, stdout) => { + let options: cp.ExecFileOptions = { cwd, env }; + let commandPath: string = npmCommandPath; + if (process.platform === 'win32') { + options = { cwd, env, shell: true }; + commandPath = `"${npmCommandPath}"`; + } + cp.execFile(commandPath, args, options, (error, stdout) => { if (!error) { try { const content = JSON.parse(stdout); diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index be4b192c67d..5ae2da4af92 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -38,7 +38,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.1: +braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -117,13 +117,13 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== +micromatch@^4.0.2, micromatch@^4.0.6: + version "4.0.7" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: - braces "^3.0.1" - picomatch "^2.0.5" + braces "^3.0.3" + picomatch "^2.3.1" minimatch@^5.1.6: version "5.1.6" @@ -151,10 +151,10 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -picomatch@^2.0.5: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^4.0.1: version "4.0.1" diff --git a/extensions/positron-python/src/test/interpreters/pythonPathUpdaterFactory.unit.test.ts b/extensions/positron-python/src/test/interpreters/pythonPathUpdaterFactory.unit.test.ts index 762c23d86c8..67a23fddccf 100644 --- a/extensions/positron-python/src/test/interpreters/pythonPathUpdaterFactory.unit.test.ts +++ b/extensions/positron-python/src/test/interpreters/pythonPathUpdaterFactory.unit.test.ts @@ -22,7 +22,7 @@ suite('Python Path Settings Updater', () => { .returns(() => workspaceService.object); serviceContainer .setup((c) => c.get(TypeMoq.It.isValue(IExperimentService))) - .returns(() => experimentsManager.object); + .returns(() => experimentsManager!.object); // Positron: Add ! to appease TS nightly serviceContainer .setup((c) => c.get(TypeMoq.It.isValue(IInterpreterPathService))) .returns(() => interpreterPathService.object); diff --git a/extensions/positron-python/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts b/extensions/positron-python/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts index bddf057d4f0..c94ef095ef7 100644 --- a/extensions/positron-python/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts +++ b/extensions/positron-python/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts @@ -72,7 +72,7 @@ suite('Execution Flow Run Adapters', () => { .returns(() => { cancellationToken.cancel(); return { - proc: mockProc, + proc: mockProc!, // Positron: Add ! to appease nightly TS out: typeMoq.Mock.ofType>>().object, dispose: () => { /* no-body */ @@ -150,7 +150,7 @@ suite('Execution Flow Run Adapters', () => { .returns(() => { cancellationToken.cancel(); return { - proc: mockProc, + proc: mockProc!, // Positron: Add ! to appease nightly TS out: typeMoq.Mock.ofType>>().object, dispose: () => { /* no-body */ diff --git a/extensions/positron-r/scripts/install-kernel.ts b/extensions/positron-r/scripts/install-kernel.ts index 8a5933ec517..1827f8e0382 100644 --- a/extensions/positron-r/scripts/install-kernel.ts +++ b/extensions/positron-r/scripts/install-kernel.ts @@ -188,7 +188,7 @@ async function downloadAndReplaceArk(version: string, switch (platform()) { case 'win32': os = 'windows-x64'; break; case 'darwin': os = 'darwin-universal'; break; - case 'linux': os = (arch() === 'arm64' ? 'linux-arm64' : 'linux-x64'); break; + case 'linux': os = (arch() === 'arm64' ? 'linux-arm64' : 'linux-x64'); break; default: { console.error(`Unsupported platform ${platform()}.`); return; diff --git a/extensions/positron-r/src/test/indentation.test.ts b/extensions/positron-r/src/test/indentation.test.ts index 57b26cce124..2d760a7d5db 100644 --- a/extensions/positron-r/src/test/indentation.test.ts +++ b/extensions/positron-r/src/test/indentation.test.ts @@ -1,3 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + * Licensed under the Elastic License 2.0. See LICENSE.txt for license information. + *--------------------------------------------------------------------------------------------*/ + import * as vscode from 'vscode'; import * as positron from 'positron'; import * as assert from 'assert'; @@ -6,6 +11,7 @@ import { CURSOR, type, withFileEditor } from './editor-utils'; import { EXTENSION_ROOT_DIR } from '../constants'; import { delay, removeLeadingLines } from '../util'; import { RSession } from '../session'; +import { env } from 'process'; const snapshotsFolder = `${EXTENSION_ROOT_DIR}/src/test/snapshots`; const snippetsPath = `${snapshotsFolder}/indentation-cases.R`; @@ -31,6 +37,17 @@ suite('Indentation', () => { // run, a failure is emitted. You can either commit the new output or discard // it if that's a bug to fix. test('Regenerate and check', async () => { + // ** TODO ** + // + // This test currently causes the entire test suite to be unexpectedly + // terminated. It's disabled on CI until we can figure out why. + // + // We use the `POSITRON_BUILD_NUMBER` environment variable to detect if + // we are running on CI; this is always set by the CI environment. + if (env['POSITRON_BUILD_NUMBER']) { + return; + } + await init(); // There doesn't seem to be a method that resolves when a language is @@ -45,7 +62,7 @@ suite('Indentation', () => { } } - let ses = await positron.runtime.startLanguageRuntime(info!.runtimeId, 'Snapshot tests') as RSession; + const ses = await positron.runtime.startLanguageRuntime(info!.runtimeId, 'Snapshot tests') as RSession; await ses.waitLsp(); const expected = fs.readFileSync(snapshotsPath, 'utf8'); diff --git a/extensions/shellscript/cgmanifest.json b/extensions/shellscript/cgmanifest.json index 6042de5a644..5535c294093 100644 --- a/extensions/shellscript/cgmanifest.json +++ b/extensions/shellscript/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "jeff-hykin/better-shell-syntax", "repositoryUrl": "https://github.com/jeff-hykin/better-shell-syntax", - "commitHash": "6d0bc37a6b8023a5fddf75bd2b4eb1e1f962e4c2" + "commitHash": "35020b0bd79a90d3b262b4c13a8bb0b33adc1f45" } }, "license": "MIT", diff --git a/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json b/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json index 759e0c59ee0..a3a4d4acf9a 100644 --- a/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json +++ b/extensions/shellscript/syntaxes/shell-unix-bash.tmLanguage.json @@ -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/jeff-hykin/better-shell-syntax/commit/6d0bc37a6b8023a5fddf75bd2b4eb1e1f962e4c2", + "version": "https://github.com/jeff-hykin/better-shell-syntax/commit/35020b0bd79a90d3b262b4c13a8bb0b33adc1f45", "name": "Shell Script", "scopeName": "source.shell", "patterns": [ @@ -1547,7 +1547,7 @@ "include": "#subshell_dollar" }, { - "begin": "(?('typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors', true); + return this.readWebTypeAcquisition(configuration) && configuration.get('typescript.tsserver.web.projectWideIntellisense.suppressSemanticErrors', false); } private readWebTypeAcquisition(configuration: vscode.WorkspaceConfiguration): boolean { - return configuration.get('typescript.tsserver.web.typeAcquisition.enabled', false); + return configuration.get('typescript.tsserver.web.typeAcquisition.enabled', true); } private readEnableRegionDiagnostics(configuration: vscode.WorkspaceConfiguration): boolean { diff --git a/extensions/typescript-language-features/src/extension.browser.ts b/extensions/typescript-language-features/src/extension.browser.ts index 3e987161325..9ad0867efc9 100644 --- a/extensions/typescript-language-features/src/extension.browser.ts +++ b/extensions/typescript-language-features/src/extension.browser.ts @@ -101,7 +101,7 @@ export async function activate(context: vscode.ExtensionContext): Promise { await startPreloadWorkspaceContentsIfNeeded(context, logger); })); - context.subscriptions.push(registerAtaSupport()); + context.subscriptions.push(registerAtaSupport(logger)); return getExtensionApi(onCompletionAccepted.event, pluginManager); } diff --git a/extensions/typescript-language-features/src/filesystems/ata.ts b/extensions/typescript-language-features/src/filesystems/ata.ts index 731ad303529..b5e43244e1b 100644 --- a/extensions/typescript-language-features/src/filesystems/ata.ts +++ b/extensions/typescript-language-features/src/filesystems/ata.ts @@ -8,8 +8,9 @@ import { conditionalRegistration, requireGlobalConfiguration } from '../language import { supportsReadableByteStreams } from '../utils/platform'; import { AutoInstallerFs } from './autoInstallerFs'; import { MemFs } from './memFs'; +import { Logger } from '../logging/logger'; -export function registerAtaSupport(): vscode.Disposable { +export function registerAtaSupport(logger: Logger): vscode.Disposable { if (!supportsReadableByteStreams()) { return vscode.Disposable.from(); } @@ -18,11 +19,14 @@ export function registerAtaSupport(): vscode.Disposable { requireGlobalConfiguration('typescript', 'tsserver.web.typeAcquisition.enabled'), ], () => { return vscode.Disposable.from( - vscode.workspace.registerFileSystemProvider('vscode-global-typings', new MemFs(), { + // Ata + vscode.workspace.registerFileSystemProvider('vscode-global-typings', new MemFs('global-typings', logger), { isCaseSensitive: true, - isReadonly: false + isReadonly: false, }), - vscode.workspace.registerFileSystemProvider('vscode-node-modules', new AutoInstallerFs(), { + + // Read accesses to node_modules + vscode.workspace.registerFileSystemProvider('vscode-node-modules', new AutoInstallerFs(logger), { isCaseSensitive: true, isReadonly: false })); diff --git a/extensions/typescript-language-features/src/filesystems/autoInstallerFs.ts b/extensions/typescript-language-features/src/filesystems/autoInstallerFs.ts index 4e69fce8cda..d639b7fe999 100644 --- a/extensions/typescript-language-features/src/filesystems/autoInstallerFs.ts +++ b/extensions/typescript-language-features/src/filesystems/autoInstallerFs.ts @@ -3,50 +3,33 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { PackageManager } from '@vscode/ts-package-manager'; +import { basename, join } from 'path'; import * as vscode from 'vscode'; -import { MemFs } from './memFs'; import { URI } from 'vscode-uri'; -import { PackageManager, FileSystem, packagePath } from '@vscode/ts-package-manager'; -import { join, basename, dirname } from 'path'; +import { Disposable } from '../utils/dispose'; +import { MemFs } from './memFs'; +import { Logger } from '../logging/logger'; const TEXT_DECODER = new TextDecoder('utf-8'); const TEXT_ENCODER = new TextEncoder(); -export class AutoInstallerFs implements vscode.FileSystemProvider { - - private readonly memfs = new MemFs(); - private readonly fs: FileSystem; - private readonly projectCache = new Map>(); - private readonly watcher: vscode.FileSystemWatcher; - private readonly _emitter = new vscode.EventEmitter(); - - readonly onDidChangeFile: vscode.Event = this._emitter.event; - - constructor() { - this.watcher = vscode.workspace.createFileSystemWatcher('**/{package.json,package-lock.json,package-lock.kdl}'); - const handler = (uri: URI) => { - const root = dirname(uri.path); - if (this.projectCache.delete(root)) { - (async () => { - const pm = new PackageManager(this.fs); - const opts = await this.getInstallOpts(uri, root); - const proj = await pm.resolveProject(root, opts); - proj.pruneExtraneous(); - // TODO: should this fire on vscode-node-modules instead? - // NB(kmarchan): This should tell TSServer that there's - // been changes inside node_modules and it needs to - // re-evaluate things. - this._emitter.fire([{ - type: vscode.FileChangeType.Changed, - uri: uri.with({ path: join(root, 'node_modules') }) - }]); - })(); - } - }; - this.watcher.onDidChange(handler); - this.watcher.onDidCreate(handler); - this.watcher.onDidDelete(handler); - const memfs = this.memfs; +export class AutoInstallerFs extends Disposable implements vscode.FileSystemProvider { + + private readonly memfs: MemFs; + private readonly packageManager: PackageManager; + private readonly _projectCache = new Map | undefined>(); + + private readonly _emitter = this._register(new vscode.EventEmitter()); + readonly onDidChangeFile = this._emitter.event; + + constructor( + private readonly logger: Logger + ) { + super(); + + const memfs = new MemFs('auto-installer', logger); + this.memfs = memfs; memfs.onDidChangeFile((e) => { this._emitter.fire(e.map(ev => ({ type: ev.type, @@ -54,7 +37,8 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { uri: ev.uri.with({ scheme: 'memfs' }) }))); }); - this.fs = { + + this.packageManager = new PackageManager({ readDirectory(path: string, _extensions?: readonly string[], _exclude?: readonly string[], _include?: readonly string[], _depth?: number): string[] { return memfs.readDirectory(URI.file(path)).map(([name, _]) => name); }, @@ -87,17 +71,17 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { return undefined; } } - }; + }); } watch(resource: vscode.Uri): vscode.Disposable { - const mapped = URI.file(new MappedUri(resource).path); - console.log('watching', mapped); - return this.memfs.watch(mapped); + this.logger.trace(`AutoInstallerFs.watch. Resource: ${resource.toString()}}`); + return this.memfs.watch(resource); } async stat(uri: vscode.Uri): Promise { - // console.log('stat', uri.toString()); + this.logger.trace(`AutoInstallerFs.stat: ${uri}`); + const mapped = new MappedUri(uri); // TODO: case sensitivity configuration @@ -119,7 +103,8 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { } async readDirectory(uri: vscode.Uri): Promise<[string, vscode.FileType][]> { - // console.log('readDirectory', uri.toString()); + this.logger.trace(`AutoInstallerFs.readDirectory: ${uri}`); + const mapped = new MappedUri(uri); await this.ensurePackageContents(mapped); @@ -127,7 +112,8 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { } async readFile(uri: vscode.Uri): Promise { - // console.log('readFile', uri.toString()); + this.logger.trace(`AutoInstallerFs.readFile: ${uri}`); + const mapped = new MappedUri(uri); await this.ensurePackageContents(mapped); @@ -151,8 +137,6 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { } private async ensurePackageContents(incomingUri: MappedUri): Promise { - // console.log('ensurePackageContents', incomingUri.path); - // If we're not looking for something inside node_modules, bail early. if (!incomingUri.path.includes('node_modules')) { throw vscode.FileSystemError.FileNotFound(); @@ -163,34 +147,37 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { throw vscode.FileSystemError.FileNotFound(); } - const root = this.getProjectRoot(incomingUri.path); - - const pkgPath = packagePath(incomingUri.path); - if (!root || this.projectCache.get(root)?.has(pkgPath)) { + const root = await this.getProjectRoot(incomingUri.original); + if (!root) { return; } - const proj = await (new PackageManager(this.fs)).resolveProject(root, await this.getInstallOpts(incomingUri.original, root)); + this.logger.trace(`AutoInstallerFs.ensurePackageContents. Path: ${incomingUri.path}, Root: ${root}`); - const restore = proj.restorePackageAt(incomingUri.path); - try { - await restore; - } catch (e) { - console.error(`failed to restore package at ${incomingUri.path}: `, e); - throw e; - } - if (!this.projectCache.has(root)) { - this.projectCache.set(root, new Set()); + const existingInstall = this._projectCache.get(root); + if (existingInstall) { + this.logger.trace(`AutoInstallerFs.ensurePackageContents. Found ongoing install for: ${root}/node_modules`); + return existingInstall; } - this.projectCache.get(root)!.add(pkgPath); + + const installing = (async () => { + const proj = await this.packageManager.resolveProject(root, await this.getInstallOpts(incomingUri.original, root)); + try { + await proj.restore(); + } catch (e) { + console.error(`failed to restore package at ${incomingUri.path}: `, e); + throw e; + } + })(); + this._projectCache.set(root, installing); + await installing; } private async getInstallOpts(originalUri: URI, root: string) { const vsfs = vscode.workspace.fs; - let pkgJson; - try { - pkgJson = TEXT_DECODER.decode(await vsfs.readFile(originalUri.with({ path: join(root, 'package.json') }))); - } catch (e) { } + + // We definitely need a package.json to be there. + const pkgJson = TEXT_DECODER.decode(await vsfs.readFile(originalUri.with({ path: join(root, 'package.json') }))); let kdlLock; try { @@ -209,13 +196,20 @@ export class AutoInstallerFs implements vscode.FileSystemProvider { }; } - private getProjectRoot(path: string): string | undefined { - const pkgPath = path.match(/(^.*)\/node_modules/); - return pkgPath?.[1]; + private async getProjectRoot(incomingUri: URI): Promise { + const vsfs = vscode.workspace.fs; + const pkgPath = incomingUri.path.match(/^(.*?)\/node_modules/); + const ret = pkgPath?.[1]; + if (!ret) { + return; + } + try { + await vsfs.stat(incomingUri.with({ path: join(ret, 'package.json') })); + return ret; + } catch (e) { + return; + } } - - // --- manage file events - } class MappedUri { @@ -227,7 +221,7 @@ class MappedUri { const parts = uri.path.match(/^\/([^\/]+)\/([^\/]*)(?:\/(.+))?$/); if (!parts) { - throw new Error(`Invalid path: ${uri.path}`); + throw new Error(`Invalid uri: ${uri.toString()}, ${uri.path}`); } const scheme = parts[1]; diff --git a/extensions/typescript-language-features/src/filesystems/memFs.ts b/extensions/typescript-language-features/src/filesystems/memFs.ts index eeeb60e957d..05c4e7c3db7 100644 --- a/extensions/typescript-language-features/src/filesystems/memFs.ts +++ b/extensions/typescript-language-features/src/filesystems/memFs.ts @@ -3,8 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; import { basename, dirname } from 'path'; +import * as vscode from 'vscode'; +import { Logger } from '../logging/logger'; export class MemFs implements vscode.FileSystemProvider { @@ -14,8 +15,13 @@ export class MemFs implements vscode.FileSystemProvider { 0, ); + constructor( + private readonly id: string, + private readonly logger: Logger, + ) { } + stat(uri: vscode.Uri): vscode.FileStat { - // console.log('stat', uri.toString()); + this.logger.trace(`MemFs.stat ${this.id}. uri: ${uri}`); const entry = this.getEntry(uri); if (!entry) { throw vscode.FileSystemError.FileNotFound(); @@ -25,7 +31,7 @@ export class MemFs implements vscode.FileSystemProvider { } readDirectory(uri: vscode.Uri): [string, vscode.FileType][] { - // console.log('readDirectory', uri.toString()); + this.logger.trace(`MemFs.readDirectory ${this.id}. uri: ${uri}`); const entry = this.getEntry(uri); if (!entry) { @@ -39,7 +45,7 @@ export class MemFs implements vscode.FileSystemProvider { } readFile(uri: vscode.Uri): Uint8Array { - // console.log('readFile', uri.toString()); + this.logger.trace(`MemFs.readFile ${this.id}. uri: ${uri}`); const entry = this.getEntry(uri); if (!entry) { @@ -54,7 +60,7 @@ export class MemFs implements vscode.FileSystemProvider { } writeFile(uri: vscode.Uri, content: Uint8Array, { create, overwrite }: { create: boolean; overwrite: boolean }): void { - // console.log('writeFile', uri.toString()); + this.logger.trace(`MemFs.writeFile ${this.id}. uri: ${uri}`); const dir = this.getParent(uri); @@ -98,7 +104,8 @@ export class MemFs implements vscode.FileSystemProvider { } createDirectory(uri: vscode.Uri): void { - // console.log('createDirectory', uri.toString()); + this.logger.trace(`MemFs.createDirectory ${this.id}. uri: ${uri}`); + const dir = this.getParent(uri); const now = Date.now() / 1000; dir.contents.set(basename(uri.path), new FsDirectoryEntry(new Map(), now, now)); diff --git a/extensions/typescript-language-features/src/languageFeatures/completions.ts b/extensions/typescript-language-features/src/languageFeatures/completions.ts index 708d7e028dd..1012083a0bf 100644 --- a/extensions/typescript-language-features/src/languageFeatures/completions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/completions.ts @@ -58,6 +58,7 @@ class MyCompletionItem extends vscode.CompletionItem { private readonly completionContext: CompletionContext, public readonly metadata: any | undefined, client: ITypeScriptServiceClient, + defaultCommitCharacters: readonly string[] | undefined, ) { const label = tsEntry.name || (tsEntry.insertText ?? ''); super(label, MyCompletionItem.convertKind(tsEntry.kind)); @@ -93,7 +94,7 @@ class MyCompletionItem extends vscode.CompletionItem { this.useCodeSnippet = completionContext.completeFunctionCalls && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method); this.range = this.getRangeFromReplacementSpan(tsEntry, completionContext); - this.commitCharacters = MyCompletionItem.getCommitCharacters(completionContext, tsEntry); + this.commitCharacters = MyCompletionItem.getCommitCharacters(completionContext, tsEntry, defaultCommitCharacters); this.insertText = isSnippet && tsEntry.insertText ? new vscode.SnippetString(tsEntry.insertText) : tsEntry.insertText; this.filterText = tsEntry.filterText || this.getFilterText(completionContext.line, tsEntry.insertText); @@ -500,7 +501,23 @@ class MyCompletionItem extends vscode.CompletionItem { } } - private static getCommitCharacters(context: CompletionContext, entry: Proto.CompletionEntry): string[] | undefined { + private static getCommitCharacters( + context: CompletionContext, + entry: Proto.CompletionEntry, + defaultCommitCharacters: readonly string[] | undefined, + ): string[] | undefined { + // @ts-expect-error until TS 5.6 + let commitCharacters = (entry.commitCharacters as string[] | undefined) ?? (defaultCommitCharacters ? Array.from(defaultCommitCharacters) : undefined); + if (commitCharacters) { + if (context.enableCallCompletions + && !context.isNewIdentifierLocation + && entry.kind !== PConst.Kind.warning + && entry.kind !== PConst.Kind.string) { + commitCharacters.push('('); + } + return commitCharacters; + } + if (entry.kind === PConst.Kind.warning || entry.kind === PConst.Kind.string) { // Ambient JS word based suggestion, strings return undefined; } @@ -509,7 +526,7 @@ class MyCompletionItem extends vscode.CompletionItem { return undefined; } - const commitCharacters: string[] = ['.', ',', ';']; + commitCharacters = ['.', ',', ';']; if (context.enableCallCompletions) { commitCharacters.push('('); } @@ -735,52 +752,40 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< triggerKind: typeConverters.CompletionTriggerKind.toProtocolCompletionTriggerKind(context.triggerKind), }; - let isNewIdentifierLocation = true; - let isIncomplete = false; - let isMemberCompletion = false; let dotAccessorContext: DotAccessorContext | undefined; - let entries: ReadonlyArray; - let metadata: any | undefined; let response: ServerResponse.Response | undefined; let duration: number | undefined; let optionalReplacementRange: vscode.Range | undefined; - if (this.client.apiVersion.gte(API.v300)) { - const startTime = Date.now(); - try { - response = await this.client.interruptGetErr(() => this.client.execute('completionInfo', args, token)); - } finally { - duration = Date.now() - startTime; - } - if (response.type !== 'response' || !response.body) { - this.logCompletionsTelemetry(duration, response); - return undefined; - } - isNewIdentifierLocation = response.body.isNewIdentifierLocation; - isMemberCompletion = response.body.isMemberCompletion; - if (isMemberCompletion) { - const dotMatch = line.text.slice(0, position.character).match(/\??\.\s*$/) || undefined; - if (dotMatch) { - const range = new vscode.Range(position.translate({ characterDelta: -dotMatch[0].length }), position); - const text = document.getText(range); - dotAccessorContext = { range, text }; - } - } - isIncomplete = !!response.body.isIncomplete || (response.metadata as any)?.isIncomplete; - entries = response.body.entries; - metadata = response.metadata; + const startTime = Date.now(); + try { + response = await this.client.interruptGetErr(() => this.client.execute('completionInfo', args, token)); + } finally { + duration = Date.now() - startTime; + } - if (response.body.optionalReplacementSpan) { - optionalReplacementRange = typeConverters.Range.fromTextSpan(response.body.optionalReplacementSpan); - } - } else { - const response = await this.client.interruptGetErr(() => this.client.execute('completions', args, token)); - if (response.type !== 'response' || !response.body) { - return undefined; + if (response.type !== 'response' || !response.body) { + this.logCompletionsTelemetry(duration, response); + return undefined; + } + const isNewIdentifierLocation = response.body.isNewIdentifierLocation; + const isMemberCompletion = response.body.isMemberCompletion; + if (isMemberCompletion) { + const dotMatch = line.text.slice(0, position.character).match(/\??\.\s*$/) || undefined; + if (dotMatch) { + const range = new vscode.Range(position.translate({ characterDelta: -dotMatch[0].length }), position); + const text = document.getText(range); + dotAccessorContext = { range, text }; } + } + const isIncomplete = !!response.body.isIncomplete || (response.metadata as any)?.isIncomplete; + const entries = response.body.entries; + const metadata = response.metadata; + // @ts-expect-error until TS 5.6 + const defaultCommitCharacters: readonly string[] | undefined = Object.freeze(response.body.defaultCommitCharacters); - entries = response.body; - metadata = response.metadata; + if (response.body.optionalReplacementSpan) { + optionalReplacementRange = typeConverters.Range.fromTextSpan(response.body.optionalReplacementSpan); } const completionContext: CompletionContext = { @@ -799,7 +804,14 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< const items: MyCompletionItem[] = []; for (const entry of entries) { if (!shouldExcludeCompletionEntry(entry, completionConfiguration)) { - const item = new MyCompletionItem(position, document, entry, completionContext, metadata, this.client); + const item = new MyCompletionItem( + position, + document, + entry, + completionContext, + metadata, + this.client, + defaultCommitCharacters); item.command = { command: ApplyCompletionCommand.ID, title: '', @@ -856,11 +868,11 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider< private getTsTriggerCharacter(context: vscode.CompletionContext): Proto.CompletionsTriggerCharacter | undefined { switch (context.triggerCharacter) { - case '@': { // Workaround for https://github.com/microsoft/TypeScript/issues/27321 - return this.client.apiVersion.gte(API.v310) && this.client.apiVersion.lt(API.v320) ? undefined : '@'; + case '@': { + return '@'; } - case '#': { // Workaround for https://github.com/microsoft/TypeScript/issues/36367 - return this.client.apiVersion.lt(API.v381) ? undefined : '#'; + case '#': { + return '#'; } case ' ': { return this.client.apiVersion.gte(API.v430) ? ' ' : undefined; diff --git a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts index bddd062b3e8..6e1ae9051b1 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts @@ -5,12 +5,12 @@ import * as path from 'path'; import * as vscode from 'vscode'; -import type * as Proto from '../tsServer/protocol/protocol'; +import * as fileSchemes from '../configuration/fileSchemes'; +import { isTypeScriptDocument } from '../configuration/languageIds'; import { API } from '../tsServer/api'; +import type * as Proto from '../tsServer/protocol/protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import { Disposable } from '../utils/dispose'; -import * as fileSchemes from '../configuration/fileSchemes'; -import { isTypeScriptDocument } from '../configuration/languageIds'; import { equals } from '../utils/objects'; import { ResourceMap } from '../utils/resourceMap'; @@ -191,6 +191,8 @@ export default class FileConfigurationManager extends Disposable { includeCompletionsWithClassMemberSnippets: config.get('suggest.classMemberSnippets.enabled', true), includeCompletionsWithObjectLiteralMethodSnippets: config.get('suggest.objectLiteralMethodSnippets.enabled', true), autoImportFileExcludePatterns: this.getAutoImportFileExcludePatternsPreference(preferencesConfig, vscode.workspace.getWorkspaceFolder(document.uri)?.uri), + // @ts-expect-error until 5.6 + autoImportSpecifierExcludeRegexes: preferencesConfig.get('autoImportSpecifierExcludeRegexes'), preferTypeOnlyAutoImports: preferencesConfig.get('preferTypeOnlyAutoImports', false), useLabelDetailsInCompletionEntries: true, allowIncompleteCompletions: true, @@ -199,6 +201,7 @@ export default class FileConfigurationManager extends Disposable { interactiveInlayHints: true, includeCompletionsForModuleExports: config.get('suggest.autoImports'), ...getInlayHintsPreferences(config), + ...this.getOrganizeImportsPreferences(preferencesConfig), }; return preferences; @@ -208,7 +211,7 @@ export default class FileConfigurationManager extends Disposable { switch (config.get('quoteStyle')) { case 'single': return 'single'; case 'double': return 'double'; - default: return this.client.apiVersion.gte(API.v333) ? 'auto' : undefined; + default: return 'auto'; } } @@ -227,6 +230,23 @@ export default class FileConfigurationManager extends Disposable { wildcardPrefix + '**' + path.sep + p; }); } + + private getOrganizeImportsPreferences(config: vscode.WorkspaceConfiguration): Proto.UserPreferences { + return { + // More specific settings + organizeImportsAccentCollation: config.get('organizeImports.accentCollation'), + organizeImportsCaseFirst: withDefaultAsUndefined(config.get<'default' | 'upper' | 'lower'>('organizeImports.caseFirst', 'default'), 'default'), + organizeImportsCollation: config.get<'ordinal' | 'unicode'>('organizeImports.collation'), + organizeImportsIgnoreCase: withDefaultAsUndefined(config.get<'auto' | 'caseInsensitive' | 'caseSensitive'>('organizeImports.caseSensitivity'), 'auto'), + organizeImportsLocale: config.get('organizeImports.locale'), + organizeImportsNumericCollation: config.get('organizeImports.numericCollation'), + organizeImportsTypeOrder: withDefaultAsUndefined(config.get<'auto' | 'last' | 'inline' | 'first'>('organizeImports.typeOrder', 'auto'), 'auto'), + }; + } +} + +function withDefaultAsUndefined(value: T, def: O): Exclude | undefined { + return value === def ? undefined : value as Exclude; } export class InlayHintSettingNames { diff --git a/extensions/typescript-language-features/src/languageFeatures/fixAll.ts b/extensions/typescript-language-features/src/languageFeatures/fixAll.ts index 690439218a8..09ab205d918 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fixAll.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fixAll.ts @@ -5,7 +5,6 @@ import * as vscode from 'vscode'; import { DocumentSelector } from '../configuration/documentSelector'; -import { API } from '../tsServer/api'; import * as errorCodes from '../tsServer/protocol/errorCodes'; import * as fixNames from '../tsServer/protocol/fixNames'; import type * as Proto from '../tsServer/protocol/protocol'; @@ -13,7 +12,7 @@ import * as typeConverters from '../typeConverters'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; import { DiagnosticsManager } from './diagnostics'; import FileConfigurationManager from './fileConfigurationManager'; -import { conditionalRegistration, requireMinVersion, requireSomeCapability } from './util/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; interface AutoFix { @@ -250,7 +249,6 @@ export function register( diagnosticsManager: DiagnosticsManager, ) { return conditionalRegistration([ - requireMinVersion(client, API.v300), requireSomeCapability(client, ClientCapability.Semantic), ], () => { const provider = new TypeScriptAutoFixProvider(client, fileConfigurationManager, diagnosticsManager); diff --git a/extensions/typescript-language-features/src/languageFeatures/rename.ts b/extensions/typescript-language-features/src/languageFeatures/rename.ts index 19dc5b93c99..5c86190a53e 100644 --- a/extensions/typescript-language-features/src/languageFeatures/rename.ts +++ b/extensions/typescript-language-features/src/languageFeatures/rename.ts @@ -36,10 +36,6 @@ class TypeScriptRenameProvider implements vscode.RenameProvider { position: vscode.Position, token: vscode.CancellationToken ): Promise { - if (this.client.apiVersion.lt(API.v310)) { - return undefined; - } - const response = await this.execRename(document, position, token); if (!response) { return undefined; diff --git a/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts b/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts index 48c9af7a5a5..7f8d60d3875 100644 --- a/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts +++ b/extensions/typescript-language-features/src/languageFeatures/semanticTokens.ts @@ -4,11 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; +import { DocumentSelector } from '../configuration/documentSelector'; import * as Proto from '../tsServer/protocol/protocol'; -import { API } from '../tsServer/api'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; -import { conditionalRegistration, requireMinVersion, requireSomeCapability } from './util/dependentRegistration'; -import { DocumentSelector } from '../configuration/documentSelector'; +import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; // as we don't do deltas, for performance reasons, don't compute semantic tokens for documents above that limit const CONTENT_LENGTH_LIMIT = 100000; @@ -18,7 +17,6 @@ export function register( client: ITypeScriptServiceClient, ) { return conditionalRegistration([ - requireMinVersion(client, API.v370), requireSomeCapability(client, ClientCapability.Semantic), ], () => { const provider = new DocumentSemanticTokensProvider(client); diff --git a/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts b/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts index 80887d65180..fa6a6096d37 100644 --- a/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts +++ b/extensions/typescript-language-features/src/languageFeatures/smartSelect.ts @@ -5,14 +5,11 @@ import * as vscode from 'vscode'; import { DocumentSelector } from '../configuration/documentSelector'; -import { API } from '../tsServer/api'; import type * as Proto from '../tsServer/protocol/protocol'; import * as typeConverters from '../typeConverters'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { conditionalRegistration, requireMinVersion } from './util/dependentRegistration'; class SmartSelection implements vscode.SelectionRangeProvider { - public static readonly minVersion = API.v350; public constructor( private readonly client: ITypeScriptServiceClient @@ -53,9 +50,5 @@ export function register( selector: DocumentSelector, client: ITypeScriptServiceClient, ) { - return conditionalRegistration([ - requireMinVersion(client, SmartSelection.minVersion), - ], () => { - return vscode.languages.registerSelectionRangeProvider(selector.syntax, new SmartSelection(client)); - }); + return vscode.languages.registerSelectionRangeProvider(selector.syntax, new SmartSelection(client)); } diff --git a/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts b/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts index 45ac08e14a4..6b47feb3d00 100644 --- a/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts +++ b/extensions/typescript-language-features/src/languageFeatures/tagClosing.ts @@ -4,17 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import type * as Proto from '../tsServer/protocol/protocol'; -import { API } from '../tsServer/api'; -import { ITypeScriptServiceClient } from '../typescriptService'; -import { Condition, conditionalRegistration, requireMinVersion } from './util/dependentRegistration'; -import { Disposable } from '../utils/dispose'; import { DocumentSelector } from '../configuration/documentSelector'; import { LanguageDescription } from '../configuration/languageDescription'; +import type * as Proto from '../tsServer/protocol/protocol'; import * as typeConverters from '../typeConverters'; +import { ITypeScriptServiceClient } from '../typescriptService'; +import { Disposable } from '../utils/dispose'; +import { Condition, conditionalRegistration } from './util/dependentRegistration'; class TagClosing extends Disposable { - public static readonly minVersion = API.v300; private _disposed = false; private _timeout: NodeJS.Timeout | undefined = undefined; @@ -167,7 +165,6 @@ export function register( client: ITypeScriptServiceClient, ) { return conditionalRegistration([ - requireMinVersion(client, TagClosing.minVersion), requireActiveDocumentSetting(selector.syntax, language) ], () => new TagClosing(client)); } diff --git a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts index 91ca9612e70..bdaa1fc69ff 100644 --- a/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts +++ b/extensions/typescript-language-features/src/languageFeatures/updatePathsOnRename.ts @@ -7,7 +7,6 @@ import * as path from 'path'; import * as vscode from 'vscode'; import * as fileSchemes from '../configuration/fileSchemes'; import { doesResourceLookLikeATypeScriptFile } from '../configuration/languageDescription'; -import { API } from '../tsServer/api'; import type * as Proto from '../tsServer/protocol/protocol'; import * as typeConverters from '../typeConverters'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; @@ -15,7 +14,7 @@ import { Delayer } from '../utils/async'; import { nulToken } from '../utils/cancellation'; import { Disposable } from '../utils/dispose'; import FileConfigurationManager from './fileConfigurationManager'; -import { conditionalRegistration, requireMinVersion, requireSomeCapability } from './util/dependentRegistration'; +import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; const updateImportsOnFileMoveName = 'updateImportsOnFileMove.enabled'; @@ -43,7 +42,6 @@ interface RenameAction { } class UpdateImportsOnFileRenameHandler extends Disposable { - public static readonly minVersion = API.v300; private readonly _delayer = new Delayer(50); private readonly _pendingRenames = new Set(); @@ -289,7 +287,6 @@ export function register( handles: (uri: vscode.Uri) => Promise, ) { return conditionalRegistration([ - requireMinVersion(client, UpdateImportsOnFileRenameHandler.minVersion), requireSomeCapability(client, ClientCapability.Semantic), ], () => { return new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles); diff --git a/extensions/typescript-language-features/src/languageFeatures/util/textRendering.ts b/extensions/typescript-language-features/src/languageFeatures/util/textRendering.ts index fe26dd64029..af1a7e601b4 100644 --- a/extensions/typescript-language-features/src/languageFeatures/util/textRendering.ts +++ b/extensions/typescript-language-features/src/languageFeatures/util/textRendering.ts @@ -15,24 +15,6 @@ export interface IFilePathToResourceConverter { toResource(filepath: string): vscode.Uri; } -function replaceLinks(text: string): string { - return text - // Http(s) links - .replace(/\{@(link|linkplain|linkcode) (https?:\/\/[^ |}]+?)(?:[| ]([^{}\n]+?))?\}/gi, (_, tag: string, link: string, text?: string) => { - switch (tag) { - case 'linkcode': - return `[\`${text ? text.trim() : link}\`](${link})`; - - default: - return `[${text ? text.trim() : link}](${link})`; - } - }); -} - -function processInlineTags(text: string): string { - return replaceLinks(text); -} - function getTagBodyText( tag: Proto.JSDocTagInfo, filePathConverter: IFilePathToResourceConverter, @@ -67,18 +49,19 @@ function getTagBodyText( case 'author': { // fix obsucated email address, #80898 const emailMatch = text.match(/(.+)\s<([-.\w]+@[-.\w]+)>/); - if (emailMatch === null) { return text; } else { return `${emailMatch[1]} ${emailMatch[2]}`; } } - case 'default': + case 'default': { return makeCodeblock(text); + } + default: { + return text; + } } - - return processInlineTags(text); } function getTagDocumentation( @@ -98,11 +81,10 @@ function getTagDocumentation( if (!doc) { return label; } - return label + (doc.match(/\r\n|\n/g) ? ' \n' + processInlineTags(doc) : ` \u2014 ${processInlineTags(doc)}`); + return label + (doc.match(/\r\n|\n/g) ? ' \n' + doc : ` \u2014 ${doc}`); } break; } - case 'return': case 'returns': { // For return(s), we require a non-empty body @@ -147,7 +129,7 @@ export function asPlainTextWithLinks( parts: readonly Proto.SymbolDisplayPart[] | string, filePathConverter: IFilePathToResourceConverter, ): string { - return processInlineTags(convertLinkTags(parts, filePathConverter)); + return convertLinkTags(parts, filePathConverter); } /** @@ -187,10 +169,10 @@ function convertLinkTags( if (text) { if (/^https?:/.test(text)) { const parts = text.split(' '); - if (parts.length === 1) { + if (parts.length === 1 && !currentLink.linkcode) { out.push(`<${parts[0]}>`); - } else if (parts.length > 1) { - const linkText = parts.slice(1).join(' '); + } else { + const linkText = parts.length > 1 ? parts.slice(1).join(' ') : parts[0]; out.push(`[${currentLink.linkcode ? '`' + escapeMarkdownSyntaxTokensForCode(linkText) + '`' : linkText}](${parts[0]})`); } } else { @@ -224,7 +206,7 @@ function convertLinkTags( break; } } - return processInlineTags(out.join('')); + return out.join(''); } function escapeMarkdownSyntaxTokensForCode(text: string): string { diff --git a/extensions/typescript-language-features/src/test/unit/textRendering.test.ts b/extensions/typescript-language-features/src/test/unit/textRendering.test.ts index b13f682f715..c2a8bafb8c0 100644 --- a/extensions/typescript-language-features/src/test/unit/textRendering.test.ts +++ b/extensions/typescript-language-features/src/test/unit/textRendering.test.ts @@ -28,17 +28,19 @@ suite('typescript.previewer', () => { test('Should parse url jsdoc @link', () => { assert.strictEqual( documentationToMarkdown( - 'x {@link http://www.example.com/foo} y {@link https://api.jquery.com/bind/#bind-eventType-eventData-handler} z', + // 'x {@link http://www.example.com/foo} y {@link https://api.jquery.com/bind/#bind-eventType-eventData-handler} z', + [{ "text": "x ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "http://www.example.com/foo", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " y ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "https://api.jquery.com/bind/#bind-eventType-eventData-handler", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " z", "kind": "text" }], [], noopToResource, undefined ).value, - 'x [http://www.example.com/foo](http://www.example.com/foo) y [https://api.jquery.com/bind/#bind-eventType-eventData-handler](https://api.jquery.com/bind/#bind-eventType-eventData-handler) z'); + 'x y z'); }); test('Should parse url jsdoc @link with text', () => { assert.strictEqual( documentationToMarkdown( - 'x {@link http://www.example.com/foo abc xyz} y {@link http://www.example.com/bar|b a z} z', + // 'x {@link http://www.example.com/foo abc xyz} y {@link http://www.example.com/bar|b a z} z', + [{ "text": "x ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "http://www.example.com/foo abc xyz", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " y ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "http://www.example.com/bar b a z", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " z", "kind": "text" }], [], noopToResource, undefined ).value, @@ -48,11 +50,12 @@ suite('typescript.previewer', () => { test('Should treat @linkcode jsdocs links as monospace', () => { assert.strictEqual( documentationToMarkdown( - 'x {@linkcode http://www.example.com/foo} y {@linkplain http://www.example.com/bar} z', + // 'x {@linkcode http://www.example.com/foo} y {@linkplain http://www.example.com/bar} z', + [{ "text": "x ", "kind": "text" }, { "text": "{@linkcode ", "kind": "link" }, { "text": "http://www.example.com/foo", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " y ", "kind": "text" }, { "text": "{@linkplain ", "kind": "link" }, { "text": "http://www.example.com/bar", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " z", "kind": "text" }], [], noopToResource, undefined ).value, - 'x [`http://www.example.com/foo`](http://www.example.com/foo) y [http://www.example.com/bar](http://www.example.com/bar) z'); + 'x [`http://www.example.com/foo`](http://www.example.com/foo) y z'); }); test('Should parse url jsdoc @link in param tag', () => { @@ -60,22 +63,13 @@ suite('typescript.previewer', () => { tagsToMarkdown([ { name: 'param', - text: 'a x {@link http://www.example.com/foo abc xyz} y {@link http://www.example.com/bar|b a z} z' + // a x {@link http://www.example.com/foo abc xyz} y {@link http://www.example.com/bar|b a z} z + text: [{ "text": "a", "kind": "parameterName" }, { "text": " ", "kind": "space" }, { "text": "x ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "http://www.example.com/foo abc xyz", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " y ", "kind": "text" }, { "text": "{@link ", "kind": "link" }, { "text": "http://www.example.com/bar b a z", "kind": "linkText" }, { "text": "}", "kind": "link" }, { "text": " z", "kind": "text" }], } ], noopToResource), '*@param* `a` — x [abc xyz](http://www.example.com/foo) y [b a z](http://www.example.com/bar) z'); }); - test('Should ignore unclosed jsdocs @link', () => { - assert.strictEqual( - documentationToMarkdown( - 'x {@link http://www.example.com/foo y {@link http://www.example.com/bar bar} z', - [], - noopToResource, undefined - ).value, - 'x {@link http://www.example.com/foo y [bar](http://www.example.com/bar) z'); - }); - test('Should support non-ascii characters in parameter name (#90108)', () => { assert.strictEqual( tagsToMarkdown([ diff --git a/extensions/typescript-language-features/src/tsServer/api.ts b/extensions/typescript-language-features/src/tsServer/api.ts index 4beb29d1b2b..b70810989ec 100644 --- a/extensions/typescript-language-features/src/tsServer/api.ts +++ b/extensions/typescript-language-features/src/tsServer/api.ts @@ -13,16 +13,7 @@ export class API { } public static readonly defaultVersion = API.fromSimpleString('1.0.0'); - public static readonly v300 = API.fromSimpleString('3.0.0'); - public static readonly v310 = API.fromSimpleString('3.1.0'); - public static readonly v314 = API.fromSimpleString('3.1.4'); - public static readonly v320 = API.fromSimpleString('3.2.0'); - public static readonly v333 = API.fromSimpleString('3.3.3'); - public static readonly v340 = API.fromSimpleString('3.4.0'); - public static readonly v350 = API.fromSimpleString('3.5.0'); - public static readonly v370 = API.fromSimpleString('3.7.0'); public static readonly v380 = API.fromSimpleString('3.8.0'); - public static readonly v381 = API.fromSimpleString('3.8.1'); public static readonly v390 = API.fromSimpleString('3.9.0'); public static readonly v400 = API.fromSimpleString('4.0.0'); public static readonly v401 = API.fromSimpleString('4.0.1'); diff --git a/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts b/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts index 2bb4d39ef26..356c1703831 100644 --- a/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/tsServer/bufferSyncSupport.ts @@ -78,24 +78,14 @@ class BufferSynchronizer { } public open(resource: vscode.Uri, args: Proto.OpenRequestArgs) { - if (this.supportsBatching) { - this.updatePending(resource, new OpenOperation(args, args.scriptKindName)); - } else { - this.client.executeWithoutWaitingForResponse('open', args); - } + this.updatePending(resource, new OpenOperation(args, args.scriptKindName)); } /** * @return Was the buffer open? */ public close(resource: vscode.Uri, filepath: string, scriptKind: ScriptKind | undefined): boolean { - if (this.supportsBatching) { - return this.updatePending(resource, new CloseOperation(filepath, scriptKind)); - } else { - const args: Proto.FileRequestArgs = { file: filepath }; - this.client.executeWithoutWaitingForResponse('close', args); - return true; - } + return this.updatePending(resource, new CloseOperation(filepath, scriptKind)); } public change(resource: vscode.Uri, filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) { @@ -103,24 +93,14 @@ class BufferSynchronizer { return; } - if (this.supportsBatching) { - this.updatePending(resource, new ChangeOperation({ - fileName: filepath, - textChanges: events.map((change): Proto.CodeEdit => ({ - newText: change.text, - start: typeConverters.Position.toLocation(change.range.start), - end: typeConverters.Position.toLocation(change.range.end), - })).reverse(), // Send the edits end-of-document to start-of-document order - })); - } else { - for (const { range, text } of events) { - const args: Proto.ChangeRequestArgs = { - insertString: text, - ...typeConverters.Range.toFormattingRequestArgs(filepath, range) - }; - this.client.executeWithoutWaitingForResponse('change', args); - } - } + this.updatePending(resource, new ChangeOperation({ + fileName: filepath, + textChanges: events.map((change): Proto.CodeEdit => ({ + newText: change.text, + start: typeConverters.Position.toLocation(change.range.start), + end: typeConverters.Position.toLocation(change.range.end), + })).reverse(), // Send the edits end-of-document to start-of-document order + })); } public reset(): void { @@ -136,12 +116,6 @@ class BufferSynchronizer { } private flush() { - if (!this.supportsBatching) { - // We've already eagerly synchronized - this._pending.clear(); - return; - } - if (this._pending.size > 0) { const closedFiles: string[] = []; const openFiles: Proto.OpenRequestArgs[] = []; @@ -158,10 +132,6 @@ class BufferSynchronizer { } } - private get supportsBatching(): boolean { - return this.client.apiVersion.gte(API.v340); - } - private updatePending(resource: vscode.Uri, op: BufferOperation): boolean { switch (op.type) { case BufferOperationType.Close: { diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts index 364c0f07dae..162fdf6d3d1 100644 --- a/extensions/typescript-language-features/src/tsServer/spawner.ts +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -116,12 +116,9 @@ export class TypeScriptServerSpawner { return CompositeServerType.Single; case SyntaxServerConfiguration.Auto: - if (version.apiVersion?.gte(API.v340)) { - return version.apiVersion?.gte(API.v400) - ? CompositeServerType.DynamicSeparateSyntax - : CompositeServerType.SeparateSyntax; - } - return CompositeServerType.Single; + return version.apiVersion?.gte(API.v400) + ? CompositeServerType.DynamicSeparateSyntax + : CompositeServerType.SeparateSyntax; } } diff --git a/extensions/typescript-language-features/src/tsconfig.ts b/extensions/typescript-language-features/src/tsconfig.ts index 04f08a128bc..e85c715e875 100644 --- a/extensions/typescript-language-features/src/tsconfig.ts +++ b/extensions/typescript-language-features/src/tsconfig.ts @@ -76,6 +76,10 @@ function inferredProjectConfigSnippet( config: TypeScriptServiceConfiguration ) { const baseConfig = inferredProjectCompilerOptions(version, projectType, config); + if (projectType === ProjectType.TypeScript) { + delete baseConfig.allowImportingTsExtensions; + } + const compilerOptions = Object.keys(baseConfig).map(key => `"${key}": ${JSON.stringify(baseConfig[key])}`); return new vscode.SnippetString(`{ "compilerOptions": { diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 59f836524b8..2d3ea9eeda6 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -30,6 +30,7 @@ import { TypeScriptVersionManager } from './tsServer/versionManager'; import { ITypeScriptVersionProvider, TypeScriptVersion } from './tsServer/versionProvider'; import { ClientCapabilities, ClientCapability, ExecConfig, ITypeScriptServiceClient, ServerResponse, TypeScriptRequests } from './typescriptService'; import { Disposable, DisposableStore, disposeAll } from './utils/dispose'; +import { hash } from './utils/hash'; import { isWeb, isWebAndHasSharedArrayBuffers } from './utils/platform'; @@ -424,22 +425,33 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.serverState = new ServerState.Running(handle, apiVersion, undefined, true); this.lastStart = Date.now(); - const hasGlobalPlugins = this.pluginManager.plugins.length > 0; + + /* __GDPR__FRAGMENT__ + "TypeScriptServerEnvCommonProperties" : { + "hasGlobalPlugins": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "globalPluginNameHashes": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + const typeScriptServerEnvCommonProperties = { + hasGlobalPlugins: this.pluginManager.plugins.length > 0, + globalPluginNameHashes: JSON.stringify(this.pluginManager.plugins.map(plugin => hash(plugin.name))), + }; + /* __GDPR__ "tsserver.spawned" : { "owner": "mjbvz", "${include}": [ - "${TypeScriptCommonProperties}" + "${TypeScriptCommonProperties}", + "${TypeScriptServerEnvCommonProperties}" ], "localTypeScriptVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "typeScriptVersionSource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "hasGlobalPlugins": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "typeScriptVersionSource": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.logTelemetry('tsserver.spawned', { + ...typeScriptServerEnvCommonProperties, localTypeScriptVersion: this.versionProvider.localVersion ? this.versionProvider.localVersion.displayName : '', typeScriptVersionSource: version.source, - hasGlobalPlugins, }); handle.onError((err: Error) => { @@ -462,12 +474,14 @@ export default class TypeScriptServiceClient extends Disposable implements IType "tsserver.error" : { "owner": "mjbvz", "${include}": [ - "${TypeScriptCommonProperties}" - ], - "hasGlobalPlugins": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "${TypeScriptCommonProperties}", + "${TypeScriptServerEnvCommonProperties}" + ] } */ - this.logTelemetry('tsserver.error', { hasGlobalPlugins }); + this.logTelemetry('tsserver.error', { + ...typeScriptServerEnvCommonProperties + }); this.serviceExited(false, apiVersion); }); @@ -481,17 +495,17 @@ export default class TypeScriptServiceClient extends Disposable implements IType "tsserver.exitWithCode" : { "owner": "mjbvz", "${include}": [ - "${TypeScriptCommonProperties}" + "${TypeScriptCommonProperties}", + "${TypeScriptServerEnvCommonProperties}" ], "code" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "hasGlobalPlugins": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + "signal" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } } */ this.logTelemetry('tsserver.exitWithCode', { + ...typeScriptServerEnvCommonProperties, code: code ?? undefined, signal: signal ?? undefined, - hasGlobalPlugins, }); if (this.token !== mytoken) { @@ -972,16 +986,16 @@ export default class TypeScriptServiceClient extends Disposable implements IType spans: diagnosticEvent.body.spans, }); } - break; + return; } case EventName.configFileDiag: this._onConfigDiagnosticsReceived.fire(event as Proto.ConfigFileDiagnosticEvent); - break; + return; case EventName.telemetry: { const body = (event as Proto.TelemetryEvent).body; this.dispatchTelemetryEvent(body); - break; + return; } case EventName.projectLanguageServiceState: { const body = (event as Proto.ProjectLanguageServiceStateEvent).body!; @@ -989,7 +1003,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.serverState.updateLanguageServiceEnabled(body.languageServiceEnabled); } this._onProjectLanguageServiceStateChanged.fire(body); - break; + return; } case EventName.projectsUpdatedInBackground: { this.loadingIndicator.reset(); @@ -997,56 +1011,66 @@ export default class TypeScriptServiceClient extends Disposable implements IType const body = (event as Proto.ProjectsUpdatedInBackgroundEvent).body; const resources = body.openFiles.map(file => this.toResource(file)); this.bufferSyncSupport.getErr(resources); - break; + return; } case EventName.beginInstallTypes: this._onDidBeginInstallTypings.fire((event as Proto.BeginInstallTypesEvent).body); - break; + return; case EventName.endInstallTypes: this._onDidEndInstallTypings.fire((event as Proto.EndInstallTypesEvent).body); - break; + return; case EventName.typesInstallerInitializationFailed: this._onTypesInstallerInitializationFailed.fire((event as Proto.TypesInstallerInitializationFailedEvent).body); - break; + return; case EventName.surveyReady: this._onSurveyReady.fire((event as Proto.SurveyReadyEvent).body); - break; + return; case EventName.projectLoadingStart: this.loadingIndicator.startedLoadingProject((event as Proto.ProjectLoadingStartEvent).body.projectName); - break; + return; case EventName.projectLoadingFinish: this.loadingIndicator.finishedLoadingProject((event as Proto.ProjectLoadingFinishEvent).body.projectName); - break; + return; + + case EventName.createDirectoryWatcher: { + const path = (event.body as Proto.CreateDirectoryWatcherEventBody).path; + if (path.startsWith(inMemoryResourcePrefix)) { + return; + } - case EventName.createDirectoryWatcher: this.createFileSystemWatcher( (event.body as Proto.CreateDirectoryWatcherEventBody).id, new vscode.RelativePattern( - vscode.Uri.file((event.body as Proto.CreateDirectoryWatcherEventBody).path), + vscode.Uri.file(path), (event.body as Proto.CreateDirectoryWatcherEventBody).recursive ? '**' : '*' ), (event.body as Proto.CreateDirectoryWatcherEventBody).ignoreUpdate ); - break; + return; + } + case EventName.createFileWatcher: { + const path = (event.body as Proto.CreateFileWatcherEventBody).path; + if (path.startsWith(inMemoryResourcePrefix)) { + return; + } - case EventName.createFileWatcher: this.createFileSystemWatcher( (event.body as Proto.CreateFileWatcherEventBody).id, new vscode.RelativePattern( - vscode.Uri.file((event.body as Proto.CreateFileWatcherEventBody).path), + vscode.Uri.file(path), '*' ) ); - break; - + return; + } case EventName.closeFileWatcher: this.closeFileSystemWatcher(event.body.id); - break; + return; case EventName.requestCompleted: { // @ts-expect-error until ts 5.6 @@ -1058,12 +1082,12 @@ export default class TypeScriptServiceClient extends Disposable implements IType const resource = this.toResource(fileData.file); return { ...fileData, - lineCount: this.bufferSyncSupport.lineCount(resource), + fileLineCount: this.bufferSyncSupport.lineCount(resource), }; }) ); } - break; + return; } } } @@ -1148,13 +1172,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.watches.set(id, disposable); } - private closeFileSystemWatcher( - id: number, - ) { + private closeFileSystemWatcher(id: number) { const existing = this.watches.get(id); - if (existing) { - existing.dispose(); - } + existing?.dispose(); } private dispatchTelemetryEvent(telemetryData: Proto.TelemetryEventBody): void { @@ -1188,6 +1208,8 @@ export default class TypeScriptServiceClient extends Disposable implements IType break; } } + + // Add plugin data here if (telemetryData.telemetryEventName === 'projectInfo') { if (this.serverState.type === ServerState.Type.Running) { this.serverState.updateTsserverVersion(properties['version']); @@ -1210,9 +1232,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } private configurePlugin(pluginName: string, configuration: {}): any { - if (this.apiVersion.gte(API.v314)) { - this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration }); - } + this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration }); } } diff --git a/extensions/typescript-language-features/src/ui/activeJsTsEditorTracker.ts b/extensions/typescript-language-features/src/ui/activeJsTsEditorTracker.ts index 3da1f5a8570..c3cae6321ff 100644 --- a/extensions/typescript-language-features/src/ui/activeJsTsEditorTracker.ts +++ b/extensions/typescript-language-features/src/ui/activeJsTsEditorTracker.ts @@ -28,6 +28,7 @@ export class ActiveJsTsEditorTracker extends Disposable { this._register(vscode.window.onDidChangeActiveTextEditor(_ => this.update())); this._register(vscode.window.onDidChangeVisibleTextEditors(_ => this.update())); + this._register(vscode.window.tabGroups.onDidChangeTabGroups(_ => this.update())); this.update(); } diff --git a/extensions/typescript-language-features/src/ui/intellisenseStatus.ts b/extensions/typescript-language-features/src/ui/intellisenseStatus.ts index 1a6ea63f427..e26e2b3719f 100644 --- a/extensions/typescript-language-features/src/ui/intellisenseStatus.ts +++ b/extensions/typescript-language-features/src/ui/intellisenseStatus.ts @@ -43,6 +43,8 @@ namespace IntellisenseState { export type State = typeof None | Pending | Resolved | typeof SyntaxOnly; } +type CreateOrOpenConfigCommandArgs = [root: vscode.Uri, projectType: ProjectType]; + export class IntellisenseStatus extends Disposable { public readonly openOpenConfigCommandId = '_typescript.openConfig'; @@ -62,7 +64,7 @@ export class IntellisenseStatus extends Disposable { commandManager.register({ id: this.openOpenConfigCommandId, - execute: async (root: vscode.Uri, projectType: ProjectType) => { + execute: async (...[root, projectType]: CreateOrOpenConfigCommandArgs) => { if (this._state.type === IntellisenseState.Type.Resolved) { await openProjectConfigOrPromptToCreate(projectType, this._client, root, this._state.configFile); } else if (this._state.type === IntellisenseState.Type.Pending) { @@ -72,7 +74,7 @@ export class IntellisenseStatus extends Disposable { }); commandManager.register({ id: this.createOrOpenConfigCommandId, - execute: async (root: vscode.Uri, projectType: ProjectType) => { + execute: async (...[root, projectType]: CreateOrOpenConfigCommandArgs) => { await openOrCreateConfig(this._client.apiVersion, projectType, root, this._client.configuration); }, }); @@ -182,7 +184,7 @@ export class IntellisenseStatus extends Disposable { title: this._state.projectType === ProjectType.TypeScript ? vscode.l10n.t("Configure tsconfig") : vscode.l10n.t("Configure jsconfig"), - arguments: [rootPath], + arguments: [rootPath, this._state.projectType] satisfies CreateOrOpenConfigCommandArgs, }; } else { statusItem.text = vscode.workspace.asRelativePath(this._state.configFile); @@ -190,7 +192,7 @@ export class IntellisenseStatus extends Disposable { statusItem.command = { command: this.openOpenConfigCommandId, title: vscode.l10n.t("Open config file"), - arguments: [rootPath], + arguments: [rootPath, this._state.projectType] satisfies CreateOrOpenConfigCommandArgs, }; } break; diff --git a/extensions/typescript-language-features/src/ui/managedFileContext.ts b/extensions/typescript-language-features/src/ui/managedFileContext.ts index 0b929f85277..1da4588a334 100644 --- a/extensions/typescript-language-features/src/ui/managedFileContext.ts +++ b/extensions/typescript-language-features/src/ui/managedFileContext.ts @@ -10,7 +10,7 @@ import { isSupportedLanguageMode } from '../configuration/languageIds'; import { Disposable } from '../utils/dispose'; import { ActiveJsTsEditorTracker } from './activeJsTsEditorTracker'; -/**E +/** * When clause context set when the current file is managed by vscode's built-in typescript extension. */ export default class ManagedFileContextManager extends Disposable { diff --git a/extensions/typescript-language-features/src/utils/async.ts b/extensions/typescript-language-features/src/utils/async.ts index db92754fd2e..9523d7fe67a 100644 --- a/extensions/typescript-language-features/src/utils/async.ts +++ b/extensions/typescript-language-features/src/utils/async.ts @@ -70,3 +70,94 @@ export function setImmediate(callback: (...args: any[]) => void, ...args: any[]) return { dispose: () => clearTimeout(handle) }; } } + + +/** + * A helper to prevent accumulation of sequential async tasks. + * + * Imagine a mail man with the sole task of delivering letters. As soon as + * a letter submitted for delivery, he drives to the destination, delivers it + * and returns to his base. Imagine that during the trip, N more letters were submitted. + * When the mail man returns, he picks those N letters and delivers them all in a + * single trip. Even though N+1 submissions occurred, only 2 deliveries were made. + * + * The throttler implements this via the queue() method, by providing it a task + * factory. Following the example: + * + * const throttler = new Throttler(); + * const letters = []; + * + * function deliver() { + * const lettersToDeliver = letters; + * letters = []; + * return makeTheTrip(lettersToDeliver); + * } + * + * function onLetterReceived(l) { + * letters.push(l); + * throttler.queue(deliver); + * } + */ +export class Throttler { + + private activePromise: Promise | null; + private queuedPromise: Promise | null; + private queuedPromiseFactory: ITask> | null; + + private isDisposed = false; + + constructor() { + this.activePromise = null; + this.queuedPromise = null; + this.queuedPromiseFactory = null; + } + + queue(promiseFactory: ITask>): Promise { + if (this.isDisposed) { + return Promise.reject(new Error('Throttler is disposed')); + } + + if (this.activePromise) { + this.queuedPromiseFactory = promiseFactory; + + if (!this.queuedPromise) { + const onComplete = () => { + this.queuedPromise = null; + + if (this.isDisposed) { + return; + } + + const result = this.queue(this.queuedPromiseFactory!); + this.queuedPromiseFactory = null; + + return result; + }; + + this.queuedPromise = new Promise(resolve => { + this.activePromise!.then(onComplete, onComplete).then(resolve); + }); + } + + return new Promise((resolve, reject) => { + this.queuedPromise!.then(resolve, reject); + }); + } + + this.activePromise = promiseFactory(); + + return new Promise((resolve, reject) => { + this.activePromise!.then((result: T) => { + this.activePromise = null; + resolve(result); + }, (err: unknown) => { + this.activePromise = null; + reject(err); + }); + }); + } + + dispose(): void { + this.isDisposed = true; + } +} diff --git a/extensions/typescript-language-features/src/utils/hash.ts b/extensions/typescript-language-features/src/utils/hash.ts new file mode 100644 index 00000000000..b009808968d --- /dev/null +++ b/extensions/typescript-language-features/src/utils/hash.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/** + * Return a hash value for an object. + */ +export function hash(obj: any, hashVal = 0): number { + switch (typeof obj) { + case 'object': + if (obj === null) { + return numberHash(349, hashVal); + } else if (Array.isArray(obj)) { + return arrayHash(obj, hashVal); + } + return objectHash(obj, hashVal); + case 'string': + return stringHash(obj, hashVal); + case 'boolean': + return booleanHash(obj, hashVal); + case 'number': + return numberHash(obj, hashVal); + case 'undefined': + return 937 * 31; + default: + return numberHash(obj, 617); + } +} + +function numberHash(val: number, initialHashVal: number): number { + return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32 +} + +function booleanHash(b: boolean, initialHashVal: number): number { + return numberHash(b ? 433 : 863, initialHashVal); +} + +function stringHash(s: string, hashVal: number) { + hashVal = numberHash(149417, hashVal); + for (let i = 0, length = s.length; i < length; i++) { + hashVal = numberHash(s.charCodeAt(i), hashVal); + } + return hashVal; +} + +function arrayHash(arr: any[], initialHashVal: number): number { + initialHashVal = numberHash(104579, initialHashVal); + return arr.reduce((hashVal, item) => hash(item, hashVal), initialHashVal); +} + +function objectHash(obj: any, initialHashVal: number): number { + initialHashVal = numberHash(181387, initialHashVal); + return Object.keys(obj).sort().reduce((hashVal, key) => { + hashVal = stringHash(key, hashVal); + return hash(obj[key], hashVal); + }, initialHashVal); +} diff --git a/extensions/typescript-language-features/web/src/fileWatcherManager.ts b/extensions/typescript-language-features/web/src/fileWatcherManager.ts index 5bbce244688..6ae4472e503 100644 --- a/extensions/typescript-language-features/web/src/fileWatcherManager.ts +++ b/extensions/typescript-language-features/web/src/fileWatcherManager.ts @@ -53,9 +53,9 @@ export class FileWatcherManager { this.watchFiles.set(path, { callback, pollingInterval, options }); const watchIds = [++this.watchId]; this.watchPort.postMessage({ type: 'watchFile', uri: uri, id: watchIds[0] }); - if (this.enabledExperimentalTypeAcquisition && looksLikeNodeModules(path)) { + if (this.enabledExperimentalTypeAcquisition && looksLikeNodeModules(path) && uri.scheme !== 'vscode-global-typings') { watchIds.push(++this.watchId); - this.watchPort.postMessage({ type: 'watchFile', uri: mapUri(uri, 'vscode-node-modules'), id: watchIds[1] }); + this.watchPort.postMessage({ type: 'watchFile', uri: mapUri(uri, 'vscode-global-typings'), id: watchIds[1] }); } return { close: () => { diff --git a/extensions/typescript-language-features/web/src/typingsInstaller/typingsInstaller.ts b/extensions/typescript-language-features/web/src/typingsInstaller/typingsInstaller.ts index 7c40993d6df..1f7790dc783 100644 --- a/extensions/typescript-language-features/web/src/typingsInstaller/typingsInstaller.ts +++ b/extensions/typescript-language-features/web/src/typingsInstaller/typingsInstaller.ts @@ -70,10 +70,12 @@ export class WebTypingsInstallerClient implements ts.server.ITypingsInstaller { break; case 'event::beginInstallTypes': case 'event::endInstallTypes': + // TODO(@zkat): maybe do something with this? + case 'action::watchTypingLocations': // Don't care. break; default: - throw new Error(`unexpected response: ${response}`); + throw new Error(`unexpected response: ${JSON.stringify(response)}`); } } diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 61828a784fb..8a1032fef2c 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -47,7 +47,6 @@ "telemetry", "terminalDataWriteEvent", "terminalDimensions", - "terminalShellIntegration", "testObserver", "textSearchProvider", "timeline", diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts index ca72f39feb8..2b1110c23bf 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/chat.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import 'mocha'; import { ChatContext, ChatRequest, ChatResult, ChatVariableLevel, Disposable, Event, EventEmitter, chat, commands } from 'vscode'; -import { DeferredPromise, asPromise, assertNoRpc, closeAllEditors, disposeAll } from '../utils'; +import { DeferredPromise, asPromise, assertNoRpc, closeAllEditors, delay, disposeAll } from '../utils'; suite('chat', () => { @@ -36,7 +36,6 @@ suite('chat', () => { const participant = chat.createChatParticipant(id, (request, context, _progress, _token) => { emitter.fire({ request, context }); }); - participant.isDefault = true; disposables.push(participant); return emitter.event; } @@ -89,7 +88,6 @@ suite('chat', () => { const participant = chat.createChatParticipant('api-test.participant', (_request, _context, _progress, _token) => { return { metadata: { key: 'value' } }; }); - participant.isDefault = true; participant.followupProvider = { provideFollowups(result, _context, _token) { deferred.complete(result); @@ -123,4 +121,33 @@ suite('chat', () => { const request3 = await asPromise(onRequest2); assert.strictEqual(request3.context.history.length, 2); // request + response = 2 }); + + test('title provider is called for first request', async () => { + let calls = 0; + const deferred = new DeferredPromise(); + const participant = chat.createChatParticipant('api-test.participant', (_request, _context, _progress, _token) => { + return { metadata: { key: 'value' } }; + }); + participant.titleProvider = { + provideChatTitle(_context, _token) { + calls++; + deferred.complete(); + return 'title'; + } + }; + disposables.push(participant); + + await commands.executeCommand('workbench.action.chat.newChat'); + commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' }); + + // Wait for title provider to be called once + await deferred.p; + assert.strictEqual(calls, 1); + + commands.executeCommand('workbench.action.chat.open', { query: '@participant /hello friend' }); + await delay(500); + + // Title provider was not called again + assert.strictEqual(calls, 1); + }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts index f9d8d6a82db..e4489090017 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/notebook.api.test.ts @@ -18,6 +18,10 @@ async function openRandomNotebookDocument() { return vscode.workspace.openNotebookDocument(uri); } +async function openUntitledNotebookDocument(data?: vscode.NotebookData) { + return vscode.workspace.openNotebookDocument('notebookCoreTest', data); +} + export async function saveAllFilesAndCloseAll() { await saveAllEditors(); await closeAllEditors(); @@ -147,6 +151,7 @@ const apiTestSerializer: vscode.NotebookSerializer = { teardown(async function () { disposeAll(testDisposables); testDisposables.length = 0; + await revertAllDirty(); await saveAllFilesAndCloseAll(); }); @@ -188,6 +193,27 @@ const apiTestSerializer: vscode.NotebookSerializer = { assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); }); + test('Opening an utitled notebook without content will only open the editor when shown.', async function () { + const document = await openUntitledNotebookDocument(); + + assert.strictEqual(vscode.window.activeNotebookEditor, undefined); + + // opening a cell-uri opens a notebook editor + await vscode.window.showNotebookDocument(document); + + assert.strictEqual(!!vscode.window.activeNotebookEditor, true); + assert.strictEqual(vscode.window.activeNotebookEditor!.notebook.uri.toString(), document.uri.toString()); + }); + + test('Opening an untitled notebook with content will open a dirty document.', async function () { + const language = 'python'; + const cell = new vscode.NotebookCellData(vscode.NotebookCellKind.Code, '', language); + const data = new vscode.NotebookData([cell]); + const doc = await vscode.workspace.openNotebookDocument('jupyter-notebook', data); + + assert.strictEqual(doc.isDirty, true); + }); + test('Cannot open notebook from cell-uri with vscode.open-command', async function () { const document = await openRandomNotebookDocument(); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index 2eb115761d1..e5d9af5791e 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -619,6 +619,7 @@ suite('vscode API - workspace', () => { test('findFiles2, exclude', () => { return vscode.workspace.findFiles2('**/image.png', { exclude: '**/sub/**' }).then((res) => { + res.forEach(r => console.log(r.toString())); assert.strictEqual(res.length, 1); }); }); diff --git a/extensions/vscode-colorize-tests/test/colorize-results/test_less.json b/extensions/vscode-colorize-tests/test/colorize-results/test_less.json index 08d8b9f4fb5..a66224dd9e6 100644 --- a/extensions/vscode-colorize-tests/test/colorize-results/test_less.json +++ b/extensions/vscode-colorize-tests/test/colorize-results/test_less.json @@ -897,16 +897,16 @@ }, { "c": " ", - "t": "source.css.less meta.property-list.less meta.property-value.less", + "t": "source.css.less meta.property-list.less meta.property-value.less variable.other.readwrite.less", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF", - "dark_modern": "default: #CCCCCC", - "hc_light": "default: #292929", - "light_modern": "default: #3B3B3B" + "dark_plus": "source.css variable: #9CDCFE", + "light_plus": "source.css variable: #E50000", + "dark_vs": "source.css variable: #9CDCFE", + "light_vs": "source.css variable: #E50000", + "hc_black": "source.css variable: #D4D4D4", + "dark_modern": "source.css variable: #9CDCFE", + "hc_light": "source.css variable: #264F78", + "light_modern": "source.css variable: #E50000" } }, { diff --git a/extensions/yaml/cgmanifest.json b/extensions/yaml/cgmanifest.json index c75a4e52f89..18882ead40a 100644 --- a/extensions/yaml/cgmanifest.json +++ b/extensions/yaml/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "RedCMD/YAML-Syntax-Highlighter", "repositoryUrl": "https://github.com/RedCMD/YAML-Syntax-Highlighter", - "commitHash": "60e2e6e24c63d5a703cb04577678a2e416edd956" + "commitHash": "d4dca9f38a654ebbb13c1b72b7881e3c5864a778" } }, "licenseDetail": [ @@ -21,7 +21,7 @@ "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." ], "license": "MIT", - "version": "1.0.1" + "version": "1.1.1" } ], "version": 1 diff --git a/extensions/yaml/package.json b/extensions/yaml/package.json index d19c507bdfe..2b0ee013964 100644 --- a/extensions/yaml/package.json +++ b/extensions/yaml/package.json @@ -57,25 +57,31 @@ "path": "./syntaxes/yaml.tmLanguage.json" }, { - "scopeName": "source.yaml.1.3", - "path": "./syntaxes/yaml-1.3.tmLanguage.json" - }, - { - "scopeName": "source.yaml.1.2", - "path": "./syntaxes/yaml-1.2.tmLanguage.json" - }, - { - "scopeName": "source.yaml.1.1", - "path": "./syntaxes/yaml-1.1.tmLanguage.json" - }, - { - "scopeName": "source.yaml.1.0", - "path": "./syntaxes/yaml-1.0.tmLanguage.json" - }, + "scopeName": "source.yaml.1.3", + "path": "./syntaxes/yaml-1.3.tmLanguage.json" + }, + { + "scopeName": "source.yaml.1.2", + "path": "./syntaxes/yaml-1.2.tmLanguage.json" + }, + { + "scopeName": "source.yaml.1.1", + "path": "./syntaxes/yaml-1.1.tmLanguage.json" + }, + { + "scopeName": "source.yaml.1.0", + "path": "./syntaxes/yaml-1.0.tmLanguage.json" + }, { "language": "yaml", "scopeName": "source.yaml", - "path": "./syntaxes/yaml.tmLanguage.json" + "path": "./syntaxes/yaml.tmLanguage.json", + "unbalancedBracketScopes": [ + "invalid.illegal", + "meta.scalar.yaml", + "storage.type.tag.shorthand.yaml", + "keyword.control.flow" + ] } ], "configurationDefaults": { diff --git a/extensions/yaml/syntaxes/yaml-1.0.tmLanguage.json b/extensions/yaml/syntaxes/yaml-1.0.tmLanguage.json index 6ca3d9bf1b8..7ae77112860 100644 --- a/extensions/yaml/syntaxes/yaml-1.0.tmLanguage.json +++ b/extensions/yaml/syntaxes/yaml-1.0.tmLanguage.json @@ -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/RedCMD/YAML-Syntax-Highlighter/commit/60e2e6e24c63d5a703cb04577678a2e416edd956", + "version": "https://github.com/RedCMD/YAML-Syntax-Highlighter/commit/dfd7e5f4f71f9695c5d8697ca57f81240165aa04", "name": "YAML 1.0", "scopeName": "source.yaml.1.0", "comment": "https://yaml.org/spec/1.0/", @@ -500,7 +500,8 @@ }, "block-map-value": { "comment": "https://yaml.org/spec/1.2.2/#rule-c-l-block-map-implicit-value", - "begin": ":(?=[\\x{85 2028 2029}\r\n\t ])", + "//": "Assumming 3rd party preprocessing variables `{{...}}` turn into valid map-keys when inside a block-mapping", + "begin": ":(?=[\\x{85 2028 2029}\r\n\t ])|(?<=}})(?=[\t ]++#|[\t ]*+$)", "while": "\\G(?![?:!\"'0-9A-Za-z$()+./;<=\\\\^_~\\[{\\x{A0}-\\x{D7FF}\\x{E000}-\\x{FFFD}\\x{010000}-\\x{10FFFF}&&[^\\x{2028 2029}]]|-[^\\x{85 2028 2029}\r\n\t ])", "beginCaptures": { "0": { diff --git a/extensions/yaml/syntaxes/yaml-1.1.tmLanguage.json b/extensions/yaml/syntaxes/yaml-1.1.tmLanguage.json index 3b7974a1a5d..57a96ac1e4f 100644 --- a/extensions/yaml/syntaxes/yaml-1.1.tmLanguage.json +++ b/extensions/yaml/syntaxes/yaml-1.1.tmLanguage.json @@ -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/RedCMD/YAML-Syntax-Highlighter/commit/60e2e6e24c63d5a703cb04577678a2e416edd956", + "version": "https://github.com/RedCMD/YAML-Syntax-Highlighter/commit/dfd7e5f4f71f9695c5d8697ca57f81240165aa04", "name": "YAML 1.1", "scopeName": "source.yaml.1.1", "comment": "https://yaml.org/spec/1.1/", @@ -641,7 +641,8 @@ }, "block-map-value": { "comment": "https://yaml.org/spec/1.2.2/#rule-c-l-block-map-implicit-value", - "begin": ":(?=[\\x{85 2028 2029}\r\n\t ])", + "//": "Assumming 3rd party preprocessing variables `{{...}}` turn into valid map-keys when inside a block-mapping", + "begin": ":(?=[\\x{85 2028 2029}\r\n\t ])|(?<=}})(?=[\t ]++#|[\t ]*+$)", "while": "\\G(?![?:!\"'0-9A-Za-z$()+./;<=\\\\^_~\\[{\\x{A0}-\\x{D7FF}\\x{E000}-\\x{FFFD}\\x{010000}-\\x{10FFFF}&&[^\\x{2028 2029}]]|-[^\\x{85 2028 2029}\r\n\t ])", "beginCaptures": { "0": { diff --git a/extensions/yaml/syntaxes/yaml-1.2.tmLanguage.json b/extensions/yaml/syntaxes/yaml-1.2.tmLanguage.json index 711f5c8e422..965b6040816 100644 --- a/extensions/yaml/syntaxes/yaml-1.2.tmLanguage.json +++ b/extensions/yaml/syntaxes/yaml-1.2.tmLanguage.json @@ -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/RedCMD/YAML-Syntax-Highlighter/commit/60e2e6e24c63d5a703cb04577678a2e416edd956", + "version": "https://github.com/RedCMD/YAML-Syntax-Highlighter/commit/d4dca9f38a654ebbb13c1b72b7881e3c5864a778", "name": "YAML 1.2", "scopeName": "source.yaml.1.2", "comment": "https://yaml.org/spec/1.2.2", @@ -37,6 +37,7 @@ ] }, { + "comment": "For when YAML is embedded inside a Markdown code-block", "begin": "\\G", "while": "\\G", "name": "meta.stream.yaml", @@ -633,7 +634,8 @@ }, "block-map-value": { "comment": "https://yaml.org/spec/1.2.2/#rule-c-l-block-map-implicit-value", - "begin": ":(?=[\r\n\t ])", + "//": "Assumming 3rd party preprocessing variables `{{...}}` turn into valid map-keys when inside a block-mapping", + "begin": ":(?=[\r\n\t ])|(?<=}})(?=[\t ]++#|[\t ]*+$)", "while": "\\G(?![?:!\"'0-9A-Za-z$()+./;<=\\\\^_~\\[{\\x{85}\\x{A0}-\\x{D7FF}\\x{E000}-\\x{FFFD}\\x{010000}-\\x{10FFFF}&&[^\\x{FEFF}]]|-[^\r\n\t ])", "beginCaptures": { "0": { diff --git a/extensions/yaml/syntaxes/yaml.tmLanguage.json b/extensions/yaml/syntaxes/yaml.tmLanguage.json index 8be76d7a3c5..3a64fbd850e 100644 --- a/extensions/yaml/syntaxes/yaml.tmLanguage.json +++ b/extensions/yaml/syntaxes/yaml.tmLanguage.json @@ -4,10 +4,21 @@ "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/RedCMD/YAML-Syntax-Highlighter/commit/274009903e20ac6dc37ba5763fb853744e28c9b2", + "version": "https://github.com/RedCMD/YAML-Syntax-Highlighter/commit/d4dca9f38a654ebbb13c1b72b7881e3c5864a778", "name": "YAML Ain't Markup Language", "scopeName": "source.yaml", "patterns": [ + { + "comment": "Support legacy FrontMatter integration", + "//": "https://github.com/microsoft/vscode-markdown-tm-grammar/pull/162", + "begin": "(?<=^-{3,}\\s*+)\\G$", + "while": "^(?! {3,0}-{3,}[ \t]*+$|[ \t]*+\\.{3}$)", + "patterns": [ + { + "include": "source.yaml.1.2" + } + ] + }, { "comment": "Default to YAML version 1.2", "include": "source.yaml.1.2" diff --git a/migrate.mjs b/migrate.mjs new file mode 100644 index 00000000000..95b0e3d6434 --- /dev/null +++ b/migrate.mjs @@ -0,0 +1,364 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +// ***************************************************************** +// * * +// * AMD-TO-ESM MIGRATION SCRIPT * +// * * +// ***************************************************************** + +import { readFileSync, writeFileSync, unlinkSync } from 'node:fs'; +import { join, extname, dirname, relative } from 'node:path'; +import { preProcessFile } from 'typescript'; +import { existsSync, mkdirSync, readdirSync, statSync } from 'fs'; +import { fileURLToPath } from 'node:url'; + +// @ts-expect-error +import watch from './build/lib/watch/index.js'; + +const enableWatching = !process.argv.includes('--disable-watch'); +const enableInPlace = process.argv.includes('--enable-in-place'); +const esmToAmd = process.argv.includes('--enable-esm-to-amd'); +const amdToEsm = !esmToAmd; + +const srcFolder = fileURLToPath(new URL('src', import.meta.url)); +const dstFolder = fileURLToPath(new URL(enableInPlace ? 'src' : 'src2', import.meta.url)); + +const binaryFileExtensions = new Set([ + '.svg', '.ttf', '.png', '.sh', '.html', '.json', '.zsh', '.scpt', '.mp3', '.fish', '.ps1', '.psm1', '.md', '.txt', '.zip', '.pdf', '.qwoff', '.jxs', '.tst', '.wuff', '.less', '.utf16le', '.snap', '.actual', '.tsx', '.scm' +]); + +function migrate() { + console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`); + console.log(`STARTING ${amdToEsm ? 'AMD->ESM' : 'ESM->AMD'} MIGRATION of ${enableInPlace ? 'src in-place' : 'src to src2'}.`); + + // installing watcher quickly to avoid missing early events + const watchSrc = enableWatching ? watch('src/**', { base: 'src', readDelay: 200 }) : undefined; + + /** @type {string[]} */ + const files = []; + readdir(srcFolder, files); + + for (const filePath of files) { + const fileContents = readFileSync(filePath); + migrateOne(filePath, fileContents); + } + + if (amdToEsm) { + writeFileSync(join(dstFolder, 'package.json'), `{"type": "module"}`); + } else { + unlinkSync(join(dstFolder, 'package.json')); + } + + if (!enableInPlace) { + writeFileSync(join(dstFolder, '.gitignore'), `*`); + } + + console.log(`~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`); + console.log(`COMPLETED ${amdToEsm ? 'AMD->ESM' : 'ESM->AMD'} MIGRATION of ${enableInPlace ? 'src in-place' : 'src to src2'}. You can now launch yarn watch-esm or yarn watch-client-esm`); + if (amdToEsm) { + console.log(`Make sure to set the environment variable VSCODE_BUILD_ESM to a string of value 'true' if you want to build VS Code`); + } + + if (watchSrc) { + console.log(`WATCHING src for changes...`); + + watchSrc.on('data', (e) => { + migrateOne(e.path, e.contents); + console.log(`Handled change event for ${e.path}.`); + }); + } +} + +/** + * @param filePath + * @param fileContents + */ +function migrateOne(filePath, fileContents) { + const fileExtension = extname(filePath); + + if (fileExtension === '.ts') { + migrateTS(filePath, fileContents.toString()); + } else if (filePath.endsWith('tsconfig.base.json')) { + const opts = JSON.parse(fileContents.toString()); + if (amdToEsm) { + opts.compilerOptions.module = 'es2022'; + opts.compilerOptions.allowSyntheticDefaultImports = true; + } else { + opts.compilerOptions.module = 'amd'; + delete opts.compilerOptions.allowSyntheticDefaultImports; + } + writeDestFile(filePath, JSON.stringify(opts, null, '\t')); + } else if (fileExtension === '.js' || fileExtension === '.cjs' || fileExtension === '.mjs' || fileExtension === '.css' || binaryFileExtensions.has(fileExtension)) { + writeDestFile(filePath, fileContents); + } else { + console.log(`ignoring ${filePath}`); + } +} + +/** + * @param fileContents + * @typedef {{pos:number;end:number;}} Import + * @return + */ +function discoverImports(fileContents) { + const info = preProcessFile(fileContents); + const search = /export .* from ['"]([^'"]+)['"]/g; + /** typedef {Import[]} */ + let result = []; + do { + const m = search.exec(fileContents); + if (!m) { + break; + } + const end = m.index + m[0].length - 2; + const pos = end - m[1].length; + result.push({ pos, end }); + } while (true); + + result = result.concat(info.importedFiles); + + result.sort((a, b) => { + return a.pos - b.pos; + }); + for (let i = 1; i < result.length; i++) { + const prev = result[i - 1]; + const curr = result[i]; + if (prev.pos === curr.pos) { + result.splice(i, 1); + i--; + } + } + return result; +} + +/** + * @param filePath + * @param fileContents + */ +function migrateTS(filePath, fileContents) { + if (filePath.endsWith('.d.ts')) { + return writeDestFile(filePath, fileContents); + } + + const imports = discoverImports(fileContents); + /** @type {Replacement[]} */ + const replacements = []; + for (let i = imports.length - 1; i >= 0; i--) { + const pos = imports[i].pos + 1; + const end = imports[i].end + 1; + const importedFilename = fileContents.substring(pos, end); + + /** @type {string|undefined} */ + let importedFilepath = undefined; + if (amdToEsm) { + if (/^vs\/css!/.test(importedFilename)) { + importedFilepath = importedFilename.substr('vs/css!'.length) + '.css'; + } else { + importedFilepath = importedFilename; + } + } else { + if (importedFilename.endsWith('.css')) { + importedFilepath = `vs/css!${importedFilename.substr(0, importedFilename.length - 4)}`; + } else if (importedFilename.endsWith('.js')) { + importedFilepath = importedFilename.substr(0, importedFilename.length - 3); + } + } + + if (typeof importedFilepath !== 'string') { + continue; + } + + /** @type {boolean} */ + let isRelativeImport; + if (amdToEsm) { + if (/(^\.\/)|(^\.\.\/)/.test(importedFilepath)) { + importedFilepath = join(dirname(filePath), importedFilepath); + isRelativeImport = true; + } else if (/^vs\//.test(importedFilepath)) { + importedFilepath = join(srcFolder, importedFilepath); + isRelativeImport = true; + } else { + importedFilepath = importedFilepath; + isRelativeImport = false; + } + } else { + importedFilepath = importedFilepath; + isRelativeImport = false; + } + + /** @type {string} */ + let replacementImport; + + if (isRelativeImport) { + replacementImport = generateRelativeImport(filePath, importedFilepath); + } else { + replacementImport = importedFilepath; + } + + replacements.push({ pos, end, text: replacementImport }); + } + + fileContents = applyReplacements(fileContents, replacements); + + writeDestFile(filePath, fileContents); +} + +/** + * @param filePath + * @param importedFilepath + */ +function generateRelativeImport(filePath, importedFilepath) { + /** @type {string} */ + let relativePath; + // See https://github.com/microsoft/TypeScript/issues/16577#issuecomment-754941937 + if (!importedFilepath.endsWith('.css') && !importedFilepath.endsWith('.cjs')) { + importedFilepath = `${importedFilepath}.js`; + } + relativePath = relative(dirname(filePath), `${importedFilepath}`); + relativePath = relativePath.replace(/\\/g, '/'); + if (!/(^\.\/)|(^\.\.\/)/.test(relativePath)) { + relativePath = './' + relativePath; + } + return relativePath; +} + +/** @typedef {{pos:number;end:number;text:string;}} Replacement */ + +/** + * @param str + * @param replacements + */ +function applyReplacements(str, replacements) { + replacements.sort((a, b) => { + return a.pos - b.pos; + }); + + /** @type {string[]} */ + const result = []; + let lastEnd = 0; + for (const replacement of replacements) { + const { pos, end, text } = replacement; + result.push(str.substring(lastEnd, pos)); + result.push(text); + lastEnd = end; + } + result.push(str.substring(lastEnd, str.length)); + return result.join(''); +} + +/** + * @param srcFilePath + * @param fileContents + */ +function writeDestFile(srcFilePath, fileContents) { + const destFilePath = srcFilePath.replace(srcFolder, dstFolder); + ensureDir(dirname(destFilePath)); + + if (/(\.ts$)|(\.js$)|(\.html$)/.test(destFilePath)) { + fileContents = toggleComments(fileContents); + } + + /** @type {Buffer | undefined} */ + let existingFileContents = undefined; + try { + existingFileContents = readFileSync(destFilePath); + } catch (err) { } + if (!buffersAreEqual(existingFileContents, fileContents)) { + writeFileSync(destFilePath, fileContents); + } + + /** + * @param fileContents + */ + function toggleComments(fileContents) { + const lines = String(fileContents).split(/\r\n|\r|\n/); + let mode = 0; + let didChange = false; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (mode === 0) { + if (amdToEsm ? /\/\/ ESM-comment-begin/.test(line) : /\/\/ ESM-uncomment-begin/.test(line)) { + mode = 1; + continue; + } + if (amdToEsm ? /\/\/ ESM-uncomment-begin/.test(line) : /\/\/ ESM-comment-begin/.test(line)) { + mode = 2; + continue; + } + continue; + } + + if (mode === 1) { + if (amdToEsm ? /\/\/ ESM-comment-end/.test(line) : /\/\/ ESM-uncomment-end/.test(line)) { + mode = 0; + continue; + } + didChange = true; + lines[i] = line.replace(/^\s*/, (match) => match + '// '); + continue; + } + + if (mode === 2) { + if (amdToEsm ? /\/\/ ESM-uncomment-end/.test(line) : /\/\/ ESM-comment-end/.test(line)) { + mode = 0; + continue; + } + didChange = true; + lines[i] = line.replace(/^(\s*)\/\/ ?/, function (_, indent) { + return indent; + }); + } + } + + if (didChange) { + return lines.join('\n'); + } + return fileContents; + } +} + +/** + * @param existingFileContents + * @param fileContents + */ +function buffersAreEqual(existingFileContents, fileContents) { + if (!existingFileContents) { + return false; + } + if (typeof fileContents === 'string') { + fileContents = Buffer.from(fileContents); + } + return existingFileContents.equals(fileContents); +} + +const ensureDirCache = new Set(); +function ensureDir(dirPath) { + if (ensureDirCache.has(dirPath)) { + return; + } + ensureDirCache.add(dirPath); + ensureDir(dirname(dirPath)); + if (!existsSync(dirPath)) { + mkdirSync(dirPath); + } +} + +function readdir(dirPath, result) { + const entries = readdirSync(dirPath); + for (const entry of entries) { + const entryPath = join(dirPath, entry); + const stat = statSync(entryPath); + if (stat.isDirectory()) { + readdir(join(dirPath, entry), result); + } else { + result.push(entryPath); + } + } +} + +migrate(); diff --git a/package.json b/package.json index f7b8602e902..1f022eaa7d6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", - "version": "1.92.0", - "distro": "60cee48df7b3ff722654e8f735255b838a86e70b", + "version": "1.93.0", + "distro": "2560b0e8d341a0b6734d28ef71b08e1920ff2501", "author": { "name": "Microsoft Corporation" }, @@ -11,13 +11,17 @@ "scripts": { "test": "echo Please run any of the test scripts from the scripts folder.", "test-browser": "npx playwright install && node test/unit/browser/index.js", + "test-browser-esm": "npx playwright install && node test/unit/browser/index.esm.js", "test-browser-no-install": "node test/unit/browser/index.js", + "test-browser-esm-no-install": "node test/unit/browser/index.esm.js", "test-node": "mocha test/unit/node/index.js --delay --ui=tdd --timeout=5000 --exit", + "test-node-esm": "mocha test/unit/node/index.mjs --delay --ui=tdd --timeout=5000 --exit", "test-extension": "vscode-test", "preinstall": "node build/npm/preinstall.js", "postinstall": "node build/npm/postinstall.js", "compile": "node --max-old-space-size=4095 ./node_modules/gulp/bin/gulp.js compile", "watch": "npm-run-all -lp watch-client watch-extensions", + "watch-esm": "npm-run-all -lp watch-client-esm watch-extensions", "watchd": "deemon yarn watch", "watch-webd": "deemon yarn watch-web", "kill-watchd": "deemon --kill yarn watch", @@ -25,6 +29,7 @@ "restart-watchd": "deemon --restart yarn watch", "restart-watch-webd": "deemon --restart yarn watch-web", "watch-client": "node --max-old-space-size=4095 ./node_modules/gulp/bin/gulp.js watch-client", + "watch-client-esm": "node --max-old-space-size=4095 ./node_modules/gulp/bin/gulp.js watch-client-esm", "watch-clientd": "deemon yarn watch-client", "kill-watch-clientd": "deemon --kill yarn watch-client", "watch-extensions": "node --max-old-space-size=8190 ./node_modules/gulp/bin/gulp.js watch-extensions watch-extension-media", @@ -79,33 +84,35 @@ "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", "@vscode/policy-watcher": "^1.1.4", - "@vscode/proxy-agent": "^0.22.0", + "@vscode/proxy-agent": "^0.23.0", "@vscode/ripgrep": "^1.15.9", "@vscode/spdlog": "^0.15.0", "@vscode/sqlite3": "5.1.6-vscode", "@vscode/sudo-prompt": "9.3.1", + "@vscode/tree-sitter-wasm": "^0.0.2", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-mutex": "^0.5.0", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "0.2.0-beta.34", - "@xterm/addon-image": "0.9.0-beta.51", - "@xterm/addon-search": "0.16.0-beta.51", - "@xterm/addon-serialize": "0.14.0-beta.51", - "@xterm/addon-unicode11": "0.9.0-beta.51", - "@xterm/addon-webgl": "0.19.0-beta.51", - "@xterm/headless": "5.6.0-beta.51", - "@xterm/xterm": "5.6.0-beta.51", + "@xterm/addon-clipboard": "0.2.0-beta.35", + "@xterm/addon-image": "0.9.0-beta.52", + "@xterm/addon-search": "0.16.0-beta.52", + "@xterm/addon-serialize": "0.14.0-beta.52", + "@xterm/addon-unicode11": "0.9.0-beta.52", + "@xterm/addon-webgl": "0.19.0-beta.52", + "@xterm/headless": "5.6.0-beta.52", + "@xterm/xterm": "5.6.0-beta.52", "he": "^1.2.0", + "http-proxy": "^1.18.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.3", - "kerberos": "2.1.1-alpha.0", + "kerberos": "2.1.1", "minimist": "^1.2.6", "native-is-elevated": "0.7.0", "native-keymap": "^3.3.5", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta11", + "node-pty": "1.1.0-beta21", "open": "^8.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -114,17 +121,18 @@ "v8-inspect-profiler": "^0.1.1", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", - "vscode-textmate": "9.0.0", + "vscode-textmate": "9.1.0", "yauzl": "^3.0.0", "yazl": "^2.4.3" }, "devDependencies": { - "@playwright/test": "^1.45.0", + "@playwright/test": "^1.46.1", "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", "@types/gulp-svgmin": "^1.2.1", "@types/he": "^1.2.0", + "@types/http-proxy": "^1.17.9", "@types/http-proxy-agent": "^2.0.1", "@types/js-yaml": "^4.0.5", "@types/kerberos": "^1.1.2", @@ -165,7 +173,7 @@ "cssnano": "^6.0.3", "debounce": "^1.0.0", "deemon": "^1.8.0", - "electron": "30.1.2", + "electron": "30.4.0", "eslint": "8.36.0", "eslint-plugin-header": "3.1.1", "eslint-plugin-jsdoc": "^46.5.0", @@ -231,7 +239,8 @@ "ts-loader": "^9.4.2", "ts-node": "^10.9.1", "tsec": "0.2.7", - "typescript": "^5.6.0-dev.20240729", + "tslib": "^2.6.3", + "typescript": "^5.7.0-dev.20240826", "util": "^0.12.4", "vscode-nls-dev": "^3.3.1", "webpack": "^5.91.0", diff --git a/product.json b/product.json index 0742ff8495e..821ade3f60d 100644 --- a/product.json +++ b/product.json @@ -55,8 +55,8 @@ }, { "name": "ms-vscode.js-debug", - "version": "1.92.0", - "sha256": "e5d0a74728292423631f79d076ecb2bc129f9637bcbc2529e48a0fd53baa69cc", + "version": "1.93.0", + "sha256": "9339cb8e6b77f554df54d79e71f533279cb76b0f9b04c207f633bfd507442b6a", "repo": "https://github.com/microsoft/vscode-js-debug", "metadata": { "id": "25629058-ddac-4e17-abba-74678e126c5d", @@ -220,6 +220,16 @@ }, "publisherDisplayName": "Quarto" } + }, + { + "name": "rstudio.rstudio-workbench", + "version": "1.5.7", + "s3Bucket": "rsw-vscode-extension", + "type": "reh-web", + "sha256": "9ac536b65c91fd86274fe2cbb2ea2c381e13ba309027044bc98438730c4fa66c", + "metadata": { + "publisherDisplayName": "Posit PBC" + } } ], "extensionsGallery": { diff --git a/remote/.yarnrc b/remote/.yarnrc index 8d07643c18e..748c8d4a77a 100644 --- a/remote/.yarnrc +++ b/remote/.yarnrc @@ -1,5 +1,5 @@ disturl "https://nodejs.org/dist" -target "20.14.0" -ms_build_id "282653" +target "20.15.1" +ms_build_id "287145" runtime "node" build_from_source "true" diff --git a/remote/package.json b/remote/package.json index 48b849c5928..74f5449bc0e 100644 --- a/remote/package.json +++ b/remote/package.json @@ -8,36 +8,46 @@ "@parcel/watcher": "2.1.0", "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/proxy-agent": "^0.22.0", + "@vscode/proxy-agent": "^0.23.0", "@vscode/ripgrep": "^1.15.9", "@vscode/spdlog": "^0.15.0", + "@vscode/tree-sitter-wasm": "^0.0.2", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "0.2.0-beta.34", - "@xterm/addon-image": "0.9.0-beta.51", - "@xterm/addon-search": "0.16.0-beta.51", - "@xterm/addon-serialize": "0.14.0-beta.51", - "@xterm/addon-unicode11": "0.9.0-beta.51", - "@xterm/addon-webgl": "0.19.0-beta.51", - "@xterm/headless": "5.6.0-beta.51", - "@xterm/xterm": "5.6.0-beta.51", + "@xterm/addon-clipboard": "0.2.0-beta.35", + "@xterm/addon-image": "0.9.0-beta.52", + "@xterm/addon-search": "0.16.0-beta.52", + "@xterm/addon-serialize": "0.14.0-beta.52", + "@xterm/addon-unicode11": "0.9.0-beta.52", + "@xterm/addon-webgl": "0.19.0-beta.52", + "@xterm/headless": "5.6.0-beta.52", + "@xterm/xterm": "5.6.0-beta.52", "cookie": "^0.4.0", + "http-proxy": "^1.18.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.3", - "kerberos": "2.1.1-alpha.0", + "kerberos": "2.1.1", "minimist": "^1.2.6", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta11", + "node-pty": "1.1.0-beta21", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", - "vscode-textmate": "9.0.0", + "vscode-textmate": "9.1.0", "yauzl": "^3.0.0", "yazl": "^2.4.3" }, + "overrides": { + "micromatch": "^4.0.6", + "braces": "^3.0.3", + "follow-redirects": "^1.15.4" + }, "resolutions": { - "node-gyp-build": "4.8.1" + "micromatch": "^4.0.6", + "node-gyp-build": "4.8.1", + "braces": "^3.0.3", + "follow-redirects": "^1.15.4" } } diff --git a/remote/reh-web/package.json b/remote/reh-web/package.json index 2ad7214361e..14ebf7b1bc2 100644 --- a/remote/reh-web/package.json +++ b/remote/reh-web/package.json @@ -8,41 +8,51 @@ "@parcel/watcher": "2.1.0", "@vscode/deviceid": "^0.1.1", "@vscode/iconv-lite-umd": "0.7.0", - "@vscode/proxy-agent": "^0.22.0", + "@vscode/proxy-agent": "^0.23.0", "@vscode/ripgrep": "^1.15.9", "@vscode/spdlog": "^0.15.0", + "@vscode/tree-sitter-wasm": "^0.0.2", "@vscode/vscode-languagedetection": "1.0.21", "@vscode/windows-process-tree": "^0.6.0", "@vscode/windows-registry": "^1.1.0", - "@xterm/addon-clipboard": "0.2.0-beta.34", - "@xterm/addon-image": "0.9.0-beta.51", - "@xterm/addon-search": "0.16.0-beta.51", - "@xterm/addon-serialize": "0.14.0-beta.51", - "@xterm/addon-unicode11": "0.9.0-beta.51", - "@xterm/addon-webgl": "0.19.0-beta.51", - "@xterm/headless": "5.6.0-beta.51", - "@xterm/xterm": "5.6.0-beta.51", + "@xterm/addon-clipboard": "0.2.0-beta.35", + "@xterm/addon-image": "0.9.0-beta.52", + "@xterm/addon-search": "0.16.0-beta.52", + "@xterm/addon-serialize": "0.14.0-beta.52", + "@xterm/addon-unicode11": "0.9.0-beta.52", + "@xterm/addon-webgl": "0.19.0-beta.52", + "@xterm/headless": "5.6.0-beta.52", + "@xterm/xterm": "5.6.0-beta.52", "cookie": "^0.4.0", "he": "^1.2.0", + "http-proxy": "^1.18.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.2", "jschardet": "3.1.3", - "kerberos": "2.1.1-alpha.0", + "kerberos": "2.1.1", "minimist": "^1.2.6", "native-watchdog": "^1.4.1", - "node-pty": "1.1.0-beta11", + "node-pty": "1.1.0-beta21", "react": "^18.2.0", "react-dom": "^18.2.0", "react-window": "^1.8.8", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", "vscode-regexpp": "^3.1.0", - "vscode-textmate": "9.0.0", + "vscode-textmate": "9.1.0", "yauzl": "^3.0.0", "yazl": "^2.4.3" }, + "overrides": { + "micromatch": "^4.0.6", + "braces": "^3.0.3", + "follow-redirects": "^1.15.4" + }, "resolutions": { - "node-gyp-build": "4.8.1" + "micromatch": "^4.0.6", + "node-gyp-build": "4.8.1", + "braces": "^3.0.3", + "follow-redirects": "^1.15.4" }, "customEntryPoints": { "react": "umd/react.production.min.js", diff --git a/remote/reh-web/yarn.lock b/remote/reh-web/yarn.lock index 02dedb500b5..54d22396454 100644 --- a/remote/reh-web/yarn.lock +++ b/remote/reh-web/yarn.lock @@ -73,10 +73,10 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== -"@vscode/proxy-agent@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.22.0.tgz#bf571509d77c02c684be8c8526b7d0ac238c25cb" - integrity sha512-TQrv456pbrjmD6G+iOoXE1Mflm+8Ic/Kny4QU7ioiYe2+0HisvqzJM/CUa3Am5SWrNjMbntTHISjgmSaSlorrA== +"@vscode/proxy-agent@^0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.23.0.tgz#1cdcf0b72c2180d705d4e304b807d9594845c90f" + integrity sha512-6lgxRrzURdWwBkk6TaB0+EYYjIWQXxry6GlVO0toBN8amIyVd3I7hLPKU9Xf+SOrLIrbdU0CLkmTOBHpPJLf/g== dependencies: "@tootallnate/once" "^3.0.0" agent-base "^7.0.1" @@ -105,6 +105,11 @@ mkdirp "^1.0.4" node-addon-api "7.1.0" +"@vscode/tree-sitter-wasm@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz#da21541d343be69bb263e9380d165e3b164ec1f0" + integrity sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw== + "@vscode/vscode-languagedetection@1.0.21": version "1.0.21" resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3" @@ -129,47 +134,47 @@ resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9" integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw== -"@xterm/addon-clipboard@0.2.0-beta.34": - version "0.2.0-beta.34" - resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.34.tgz#9a753601e69d3f9aad10e6d22b3a3d05be237d6a" - integrity sha512-Iduj2jGO37VkFLrRzxK5SkE7b2bAPaIvkvcSnw5JCdsvu9cjmPy7jgJkvUu54Tltzt55X+YTkQQ2GIKHqcor8A== +"@xterm/addon-clipboard@0.2.0-beta.35": + version "0.2.0-beta.35" + resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.35.tgz#4c9b553ea63ce02a3c8075fea7df1637d52092ef" + integrity sha512-B8AulZEjsfvSEaLKp8oyRu7yJ7FJb5R3W0wpPbI/rOMVAuBwxDJsz0CxLvJUXnJX7OJwd5cjnyTnEcXJfMJycA== dependencies: js-base64 "^3.7.5" -"@xterm/addon-image@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.51.tgz#832be645ab04de3ab1af28aa37d4c3bcc72d9960" - integrity sha512-u8f0C8Kae8d8jGo2OGaxy1j4hvXOij41ZUp5fNsGL3quYufwmtVixVHUnc7WfEMVdSaSBNqfDXE+qpV4i3C3ng== - -"@xterm/addon-search@0.16.0-beta.51": - version "0.16.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.51.tgz#4595c6294287a2560abe4b76f6ef2f0aafd2f05e" - integrity sha512-DhnNDP9bAd/7/9TW+0N3BUaF/6Fpv/6RiIiromlzSu+6g1VDmuWsd8JpeTxErOCoWZuEMLpVVje9ky3yj8pN9A== - -"@xterm/addon-serialize@0.14.0-beta.51": - version "0.14.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.51.tgz#0c9802ba94018e94a727abc9e977a2349279468f" - integrity sha512-EjKIOuzSP+HCtk05iwHk0N3jYfsx81bKRv4pfGXKsc3rN0H6gQ+bvx/abSkndtgIjKtee2cy1H8pggMaezmzIA== - -"@xterm/addon-unicode11@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.51.tgz#c2f2b1ad14b2481648ca7deaa0bf2923d987e2e6" - integrity sha512-6FmA4MOue7SDYjSLmuG8rZC2eeVZ+YjhWEXWiUAAoiZ9X11j9HMdOhWcutca3crAMc6mrHfjx6fNsUxwtELMkQ== - -"@xterm/addon-webgl@0.19.0-beta.51": - version "0.19.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.51.tgz#14cb115d45c140525eb51427e236189dd800c20c" - integrity sha512-oO6yVuVA+9kNA47bT2c2IkGj9eLWvV6mEEo8wHKN7WXyYUFgw6ivAgmdrIdnKh679xbCq7th3GfcESwwQFH/sg== - -"@xterm/headless@5.6.0-beta.51": - version "5.6.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.51.tgz#76ff548a88305fe476a7d3f991331c0393c0af45" - integrity sha512-ehd4L3c28mQKVEd5cMmUzR1f1XcAVbJukfR1YiD7ohjphHUxSsg6mYb5qGIh50SsQsDI6wHYuIvmNSjvNgHVOw== - -"@xterm/xterm@5.6.0-beta.51": - version "5.6.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.51.tgz#3b9a5016d9588eb0a05226f6fc090b48a85b7698" - integrity sha512-0i9gkiP2hhCMIRk5ACM8LJXHRd1umzC27ZDHD8n14vutrQRgdW4ENvCdmrWHiVJy4Ui1t7m70zdgg72shOgcEA== +"@xterm/addon-image@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.52.tgz#a3115a50f884e5ba2f8ce09118a3d7e833fceb7b" + integrity sha512-1fWhnCIvLeO0aQ3CKqkTB9ye1bUsocpgFdDOgmwfW4XhLXpvu+QcyMGQMtWJHt8JWBN2w0cgR9eyfKw7orN+9Q== + +"@xterm/addon-search@0.16.0-beta.52": + version "0.16.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.52.tgz#f8c77629b95ceff7d6b93d95c4b085857f405470" + integrity sha512-ZLVh0O91dcjxCjrU3vadl+40Z/mBnYXhKNA58oU/dGWFtFxtUB9SaZoOUtBvnfDpQIloYAK6raC2AfVsKHzD8A== + +"@xterm/addon-serialize@0.14.0-beta.52": + version "0.14.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.52.tgz#19708cdd2895ddbd983b771ae9d14d7bc54cf7c9" + integrity sha512-1+ckKya1OURFmELH1Tjjoxz3Gnj78Dxj+NNRrEunfINkvyzaY+n8wT28FQxIlU5gJq+a0VGvlhNgTkMwgOn6aw== + +"@xterm/addon-unicode11@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.52.tgz#15afdf03c20d2e46b4eca68bd461eea71c8dd37f" + integrity sha512-5tZR/8c+vf0YNSYS6B9pEv8gyWWZpPYOf/BRQDkTGtYAnFf04MzggVE/U7tKUXGDzBhzwTPODq5qPNTX1xpGgw== + +"@xterm/addon-webgl@0.19.0-beta.52": + version "0.19.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.52.tgz#695b20a5fa88ff92e115624149592080fad59594" + integrity sha512-kbPO9iR166xW8qgRkYmKX2Vu0kQHXpxYLQ9jY/01e5kvNrI/rqRDV63FIq14ncOi7N3+dmTuUkjvbg8anCpuIw== + +"@xterm/headless@5.6.0-beta.52": + version "5.6.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.52.tgz#7f934a7d7c5bbf88e2d78c22317cd2464bc9638a" + integrity sha512-f4QITQwotblRLW6YOHnK801wHJWfFDnjD7jUEwaaAXtSp32xH3jguWnMP9/uuQX45q9ndjDjnm1t5aXX7gwqBQ== + +"@xterm/xterm@5.6.0-beta.52": + version "5.6.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.52.tgz#ed7456a8b78ea1d00431737d078b5ab0bafbcdfe" + integrity sha512-aZh8IBdZPb2N4NjTt/fQ/C90z/PM3Zxkfoqhmlsp5+v3Otmyw5kd3DepeHK1SFW/pz0/xdj4KFgX8t8Y2lDRbA== agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: version "7.1.1" @@ -260,6 +265,11 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -284,6 +294,11 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +follow-redirects@^1.0.0, follow-redirects@^1.15.4: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -321,6 +336,15 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + https-proxy-agent@^7.0.2: version "7.0.5" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" @@ -398,10 +422,10 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -kerberos@2.1.1-alpha.0: - version "2.1.1-alpha.0" - resolved "https://registry.yarnpkg.com/kerberos/-/kerberos-2.1.1-alpha.0.tgz#c6d377b43c8206340fd184167754f2c81dad5ab1" - integrity sha512-II8N/ky/Vpd8y7LTxwCuAYoQ8XeV3HYxuK7IDmyoFacIhDljx4sdt/+sOwqgXEweQyCHlbZSKSaK82upqNM4Hw== +kerberos@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/kerberos/-/kerberos-2.1.1.tgz#170fc64d1a23e8c6d6ae2736d01189e2a1dbe0f7" + integrity sha512-414s1G/qgK2T60cXnZsHbtRj8Ynjg0DBlQWeY99tkyqQ2e8vGgFHvxRdvjTlLHg/SxBA0zLQcGE6Pk6Dfq/BCA== dependencies: bindings "^1.5.0" node-addon-api "^6.1.0" @@ -419,10 +443,10 @@ loose-envify@^1.1.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -micromatch@^4.0.5: - version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" - integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== +micromatch@^4.0.5, micromatch@^4.0.6: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" picomatch "^2.3.1" @@ -494,10 +518,10 @@ node-gyp-build@4.8.1, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== -node-pty@1.1.0-beta11: - version "1.1.0-beta11" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta11.tgz#909d5dd8f9aa2a7857e7b632fd4d2d4768bdf69f" - integrity sha512-vTjF+VrvSCfPDILUkIT+YrG1Fdn06/eBRS2fc9a3JzYAvknMB1Ip8aoJhxl8hNpjWAbprmCEiV91mlfNpCD+GQ== +node-pty@1.1.0-beta21: + version "1.1.0-beta21" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta21.tgz#d75c1dfe4ff2c173459c974df72e91a4eae6dc52" + integrity sha512-FYpnY9g8qMQLTpqyeY9NVli6YfCWwvG6v6gmaDBbPjlc1VMp/+Zivq0SStDrRr1aciGnFCZzpL0BzdMnmbDnAw== dependencies: node-addon-api "^7.1.0" @@ -596,6 +620,11 @@ regenerator-runtime@^0.14.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -731,10 +760,10 @@ vscode-regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/vscode-regexpp/-/vscode-regexpp-3.1.0.tgz#42d059b6fffe99bd42939c0d013f632f0cad823f" integrity sha512-pqtN65VC1jRLawfluX4Y80MMG0DHJydWhe5ZwMHewZD6sys4LbU6lHwFAHxeuaVE6Y6+xZOtAw+9hvq7/0ejkg== -vscode-textmate@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" - integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== +vscode-textmate@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.1.0.tgz#656a6aa163a9578397ba810733952bedb2b47202" + integrity sha512-lxKSVp2DkFOx9RDAvpiYUrB9/KT1fAfi1aE8CBGstP8N7rLF+Seifj8kDA198X0mYj1CjQUC+81+nQf8CO0nVA== wrappy@1: version "1.0.2" diff --git a/remote/web/package.json b/remote/web/package.json index 646d7f06a3d..4917ee0baff 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -6,14 +6,15 @@ "@microsoft/1ds-core-js": "^3.2.13", "@microsoft/1ds-post-js": "^3.2.13", "@vscode/iconv-lite-umd": "0.7.0", + "@vscode/tree-sitter-wasm": "^0.0.2", "@vscode/vscode-languagedetection": "1.0.21", - "@xterm/addon-clipboard": "0.2.0-beta.34", - "@xterm/addon-image": "0.9.0-beta.51", - "@xterm/addon-search": "0.16.0-beta.51", - "@xterm/addon-serialize": "0.14.0-beta.51", - "@xterm/addon-unicode11": "0.9.0-beta.51", - "@xterm/addon-webgl": "0.19.0-beta.51", - "@xterm/xterm": "5.6.0-beta.51", + "@xterm/addon-clipboard": "0.2.0-beta.35", + "@xterm/addon-image": "0.9.0-beta.52", + "@xterm/addon-search": "0.16.0-beta.52", + "@xterm/addon-serialize": "0.14.0-beta.52", + "@xterm/addon-unicode11": "0.9.0-beta.52", + "@xterm/addon-webgl": "0.19.0-beta.52", + "@xterm/xterm": "5.6.0-beta.52", "he": "^1.2.0", "jschardet": "3.1.3", "react": "^18.2.0", @@ -21,10 +22,9 @@ "react-window": "^1.8.8", "tas-client-umd": "0.2.0", "vscode-oniguruma": "1.7.0", - "vscode-textmate": "9.0.0" + "vscode-textmate": "9.1.0" }, - "customEntryPoints": { "react": "umd/react.production.min.js", "react-dom": "umd/react-dom.production.min.js", diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index bdad28f01c9..ccc950add2a 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -50,47 +50,52 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== +"@vscode/tree-sitter-wasm@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz#da21541d343be69bb263e9380d165e3b164ec1f0" + integrity sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw== + "@vscode/vscode-languagedetection@1.0.21": version "1.0.21" resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3" integrity sha512-zSUH9HYCw5qsCtd7b31yqkpaCU6jhtkKLkvOOA8yTrIRfBSOFb8PPhgmMicD7B/m+t4PwOJXzU1XDtrM9Fd3/g== -"@xterm/addon-clipboard@0.2.0-beta.34": - version "0.2.0-beta.34" - resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.34.tgz#9a753601e69d3f9aad10e6d22b3a3d05be237d6a" - integrity sha512-Iduj2jGO37VkFLrRzxK5SkE7b2bAPaIvkvcSnw5JCdsvu9cjmPy7jgJkvUu54Tltzt55X+YTkQQ2GIKHqcor8A== +"@xterm/addon-clipboard@0.2.0-beta.35": + version "0.2.0-beta.35" + resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.35.tgz#4c9b553ea63ce02a3c8075fea7df1637d52092ef" + integrity sha512-B8AulZEjsfvSEaLKp8oyRu7yJ7FJb5R3W0wpPbI/rOMVAuBwxDJsz0CxLvJUXnJX7OJwd5cjnyTnEcXJfMJycA== dependencies: js-base64 "^3.7.5" -"@xterm/addon-image@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.51.tgz#832be645ab04de3ab1af28aa37d4c3bcc72d9960" - integrity sha512-u8f0C8Kae8d8jGo2OGaxy1j4hvXOij41ZUp5fNsGL3quYufwmtVixVHUnc7WfEMVdSaSBNqfDXE+qpV4i3C3ng== +"@xterm/addon-image@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.52.tgz#a3115a50f884e5ba2f8ce09118a3d7e833fceb7b" + integrity sha512-1fWhnCIvLeO0aQ3CKqkTB9ye1bUsocpgFdDOgmwfW4XhLXpvu+QcyMGQMtWJHt8JWBN2w0cgR9eyfKw7orN+9Q== -"@xterm/addon-search@0.16.0-beta.51": - version "0.16.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.51.tgz#4595c6294287a2560abe4b76f6ef2f0aafd2f05e" - integrity sha512-DhnNDP9bAd/7/9TW+0N3BUaF/6Fpv/6RiIiromlzSu+6g1VDmuWsd8JpeTxErOCoWZuEMLpVVje9ky3yj8pN9A== +"@xterm/addon-search@0.16.0-beta.52": + version "0.16.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.52.tgz#f8c77629b95ceff7d6b93d95c4b085857f405470" + integrity sha512-ZLVh0O91dcjxCjrU3vadl+40Z/mBnYXhKNA58oU/dGWFtFxtUB9SaZoOUtBvnfDpQIloYAK6raC2AfVsKHzD8A== -"@xterm/addon-serialize@0.14.0-beta.51": - version "0.14.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.51.tgz#0c9802ba94018e94a727abc9e977a2349279468f" - integrity sha512-EjKIOuzSP+HCtk05iwHk0N3jYfsx81bKRv4pfGXKsc3rN0H6gQ+bvx/abSkndtgIjKtee2cy1H8pggMaezmzIA== +"@xterm/addon-serialize@0.14.0-beta.52": + version "0.14.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.52.tgz#19708cdd2895ddbd983b771ae9d14d7bc54cf7c9" + integrity sha512-1+ckKya1OURFmELH1Tjjoxz3Gnj78Dxj+NNRrEunfINkvyzaY+n8wT28FQxIlU5gJq+a0VGvlhNgTkMwgOn6aw== -"@xterm/addon-unicode11@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.51.tgz#c2f2b1ad14b2481648ca7deaa0bf2923d987e2e6" - integrity sha512-6FmA4MOue7SDYjSLmuG8rZC2eeVZ+YjhWEXWiUAAoiZ9X11j9HMdOhWcutca3crAMc6mrHfjx6fNsUxwtELMkQ== +"@xterm/addon-unicode11@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.52.tgz#15afdf03c20d2e46b4eca68bd461eea71c8dd37f" + integrity sha512-5tZR/8c+vf0YNSYS6B9pEv8gyWWZpPYOf/BRQDkTGtYAnFf04MzggVE/U7tKUXGDzBhzwTPODq5qPNTX1xpGgw== -"@xterm/addon-webgl@0.19.0-beta.51": - version "0.19.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.51.tgz#14cb115d45c140525eb51427e236189dd800c20c" - integrity sha512-oO6yVuVA+9kNA47bT2c2IkGj9eLWvV6mEEo8wHKN7WXyYUFgw6ivAgmdrIdnKh679xbCq7th3GfcESwwQFH/sg== +"@xterm/addon-webgl@0.19.0-beta.52": + version "0.19.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.52.tgz#695b20a5fa88ff92e115624149592080fad59594" + integrity sha512-kbPO9iR166xW8qgRkYmKX2Vu0kQHXpxYLQ9jY/01e5kvNrI/rqRDV63FIq14ncOi7N3+dmTuUkjvbg8anCpuIw== -"@xterm/xterm@5.6.0-beta.51": - version "5.6.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.51.tgz#3b9a5016d9588eb0a05226f6fc090b48a85b7698" - integrity sha512-0i9gkiP2hhCMIRk5ACM8LJXHRd1umzC27ZDHD8n14vutrQRgdW4ENvCdmrWHiVJy4Ui1t7m70zdgg72shOgcEA== +"@xterm/xterm@5.6.0-beta.52": + version "5.6.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.52.tgz#ed7456a8b78ea1d00431737d078b5ab0bafbcdfe" + integrity sha512-aZh8IBdZPb2N4NjTt/fQ/C90z/PM3Zxkfoqhmlsp5+v3Otmyw5kd3DepeHK1SFW/pz0/xdj4KFgX8t8Y2lDRbA== he@^1.2.0: version "1.2.0" @@ -169,7 +174,7 @@ vscode-oniguruma@1.7.0: resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== -vscode-textmate@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" - integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== +vscode-textmate@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.1.0.tgz#656a6aa163a9578397ba810733952bedb2b47202" + integrity sha512-lxKSVp2DkFOx9RDAvpiYUrB9/KT1fAfi1aE8CBGstP8N7rLF+Seifj8kDA198X0mYj1CjQUC+81+nQf8CO0nVA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 38f916a284e..cdf3d877185 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -66,10 +66,10 @@ resolved "https://registry.yarnpkg.com/@vscode/iconv-lite-umd/-/iconv-lite-umd-0.7.0.tgz#d2f1e0664ee6036408f9743fee264ea0699b0e48" integrity sha512-bRRFxLfg5dtAyl5XyiVWz/ZBPahpOpPrNYnnHpOpUZvam4tKH35wdhP4Kj6PbM0+KdliOsPzbGWpkxcdpNB/sg== -"@vscode/proxy-agent@^0.22.0": - version "0.22.0" - resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.22.0.tgz#bf571509d77c02c684be8c8526b7d0ac238c25cb" - integrity sha512-TQrv456pbrjmD6G+iOoXE1Mflm+8Ic/Kny4QU7ioiYe2+0HisvqzJM/CUa3Am5SWrNjMbntTHISjgmSaSlorrA== +"@vscode/proxy-agent@^0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@vscode/proxy-agent/-/proxy-agent-0.23.0.tgz#1cdcf0b72c2180d705d4e304b807d9594845c90f" + integrity sha512-6lgxRrzURdWwBkk6TaB0+EYYjIWQXxry6GlVO0toBN8amIyVd3I7hLPKU9Xf+SOrLIrbdU0CLkmTOBHpPJLf/g== dependencies: "@tootallnate/once" "^3.0.0" agent-base "^7.0.1" @@ -98,6 +98,11 @@ mkdirp "^1.0.4" node-addon-api "7.1.0" +"@vscode/tree-sitter-wasm@^0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@vscode/tree-sitter-wasm/-/tree-sitter-wasm-0.0.2.tgz#da21541d343be69bb263e9380d165e3b164ec1f0" + integrity sha512-N57MR/kt4jR0H/TXeDsVYeJmvvUiK7avow0fjy+/EeKcyNBJcM2BFhj4XOAaaMbhGsOcIeSvJFouRWctXI7sKw== + "@vscode/vscode-languagedetection@1.0.21": version "1.0.21" resolved "https://registry.yarnpkg.com/@vscode/vscode-languagedetection/-/vscode-languagedetection-1.0.21.tgz#89b48f293f6aa3341bb888c1118d16ff13b032d3" @@ -122,47 +127,47 @@ resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9" integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw== -"@xterm/addon-clipboard@0.2.0-beta.34": - version "0.2.0-beta.34" - resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.34.tgz#9a753601e69d3f9aad10e6d22b3a3d05be237d6a" - integrity sha512-Iduj2jGO37VkFLrRzxK5SkE7b2bAPaIvkvcSnw5JCdsvu9cjmPy7jgJkvUu54Tltzt55X+YTkQQ2GIKHqcor8A== +"@xterm/addon-clipboard@0.2.0-beta.35": + version "0.2.0-beta.35" + resolved "https://registry.yarnpkg.com/@xterm/addon-clipboard/-/addon-clipboard-0.2.0-beta.35.tgz#4c9b553ea63ce02a3c8075fea7df1637d52092ef" + integrity sha512-B8AulZEjsfvSEaLKp8oyRu7yJ7FJb5R3W0wpPbI/rOMVAuBwxDJsz0CxLvJUXnJX7OJwd5cjnyTnEcXJfMJycA== dependencies: js-base64 "^3.7.5" -"@xterm/addon-image@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.51.tgz#832be645ab04de3ab1af28aa37d4c3bcc72d9960" - integrity sha512-u8f0C8Kae8d8jGo2OGaxy1j4hvXOij41ZUp5fNsGL3quYufwmtVixVHUnc7WfEMVdSaSBNqfDXE+qpV4i3C3ng== - -"@xterm/addon-search@0.16.0-beta.51": - version "0.16.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.51.tgz#4595c6294287a2560abe4b76f6ef2f0aafd2f05e" - integrity sha512-DhnNDP9bAd/7/9TW+0N3BUaF/6Fpv/6RiIiromlzSu+6g1VDmuWsd8JpeTxErOCoWZuEMLpVVje9ky3yj8pN9A== - -"@xterm/addon-serialize@0.14.0-beta.51": - version "0.14.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.51.tgz#0c9802ba94018e94a727abc9e977a2349279468f" - integrity sha512-EjKIOuzSP+HCtk05iwHk0N3jYfsx81bKRv4pfGXKsc3rN0H6gQ+bvx/abSkndtgIjKtee2cy1H8pggMaezmzIA== - -"@xterm/addon-unicode11@0.9.0-beta.51": - version "0.9.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.51.tgz#c2f2b1ad14b2481648ca7deaa0bf2923d987e2e6" - integrity sha512-6FmA4MOue7SDYjSLmuG8rZC2eeVZ+YjhWEXWiUAAoiZ9X11j9HMdOhWcutca3crAMc6mrHfjx6fNsUxwtELMkQ== - -"@xterm/addon-webgl@0.19.0-beta.51": - version "0.19.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.51.tgz#14cb115d45c140525eb51427e236189dd800c20c" - integrity sha512-oO6yVuVA+9kNA47bT2c2IkGj9eLWvV6mEEo8wHKN7WXyYUFgw6ivAgmdrIdnKh679xbCq7th3GfcESwwQFH/sg== - -"@xterm/headless@5.6.0-beta.51": - version "5.6.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.51.tgz#76ff548a88305fe476a7d3f991331c0393c0af45" - integrity sha512-ehd4L3c28mQKVEd5cMmUzR1f1XcAVbJukfR1YiD7ohjphHUxSsg6mYb5qGIh50SsQsDI6wHYuIvmNSjvNgHVOw== - -"@xterm/xterm@5.6.0-beta.51": - version "5.6.0-beta.51" - resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.51.tgz#3b9a5016d9588eb0a05226f6fc090b48a85b7698" - integrity sha512-0i9gkiP2hhCMIRk5ACM8LJXHRd1umzC27ZDHD8n14vutrQRgdW4ENvCdmrWHiVJy4Ui1t7m70zdgg72shOgcEA== +"@xterm/addon-image@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-image/-/addon-image-0.9.0-beta.52.tgz#a3115a50f884e5ba2f8ce09118a3d7e833fceb7b" + integrity sha512-1fWhnCIvLeO0aQ3CKqkTB9ye1bUsocpgFdDOgmwfW4XhLXpvu+QcyMGQMtWJHt8JWBN2w0cgR9eyfKw7orN+9Q== + +"@xterm/addon-search@0.16.0-beta.52": + version "0.16.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-search/-/addon-search-0.16.0-beta.52.tgz#f8c77629b95ceff7d6b93d95c4b085857f405470" + integrity sha512-ZLVh0O91dcjxCjrU3vadl+40Z/mBnYXhKNA58oU/dGWFtFxtUB9SaZoOUtBvnfDpQIloYAK6raC2AfVsKHzD8A== + +"@xterm/addon-serialize@0.14.0-beta.52": + version "0.14.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-serialize/-/addon-serialize-0.14.0-beta.52.tgz#19708cdd2895ddbd983b771ae9d14d7bc54cf7c9" + integrity sha512-1+ckKya1OURFmELH1Tjjoxz3Gnj78Dxj+NNRrEunfINkvyzaY+n8wT28FQxIlU5gJq+a0VGvlhNgTkMwgOn6aw== + +"@xterm/addon-unicode11@0.9.0-beta.52": + version "0.9.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-unicode11/-/addon-unicode11-0.9.0-beta.52.tgz#15afdf03c20d2e46b4eca68bd461eea71c8dd37f" + integrity sha512-5tZR/8c+vf0YNSYS6B9pEv8gyWWZpPYOf/BRQDkTGtYAnFf04MzggVE/U7tKUXGDzBhzwTPODq5qPNTX1xpGgw== + +"@xterm/addon-webgl@0.19.0-beta.52": + version "0.19.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/addon-webgl/-/addon-webgl-0.19.0-beta.52.tgz#695b20a5fa88ff92e115624149592080fad59594" + integrity sha512-kbPO9iR166xW8qgRkYmKX2Vu0kQHXpxYLQ9jY/01e5kvNrI/rqRDV63FIq14ncOi7N3+dmTuUkjvbg8anCpuIw== + +"@xterm/headless@5.6.0-beta.52": + version "5.6.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/headless/-/headless-5.6.0-beta.52.tgz#7f934a7d7c5bbf88e2d78c22317cd2464bc9638a" + integrity sha512-f4QITQwotblRLW6YOHnK801wHJWfFDnjD7jUEwaaAXtSp32xH3jguWnMP9/uuQX45q9ndjDjnm1t5aXX7gwqBQ== + +"@xterm/xterm@5.6.0-beta.52": + version "5.6.0-beta.52" + resolved "https://registry.yarnpkg.com/@xterm/xterm/-/xterm-5.6.0-beta.52.tgz#ed7456a8b78ea1d00431737d078b5ab0bafbcdfe" + integrity sha512-aZh8IBdZPb2N4NjTt/fQ/C90z/PM3Zxkfoqhmlsp5+v3Otmyw5kd3DepeHK1SFW/pz0/xdj4KFgX8t8Y2lDRbA== agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" @@ -199,7 +204,7 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" -braces@^3.0.2: +braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -260,6 +265,11 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -284,6 +294,11 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +follow-redirects@^1.0.0, follow-redirects@^1.15.4: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" @@ -316,6 +331,15 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + https-proxy-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" @@ -388,10 +412,10 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -kerberos@2.1.1-alpha.0: - version "2.1.1-alpha.0" - resolved "https://registry.yarnpkg.com/kerberos/-/kerberos-2.1.1-alpha.0.tgz#c6d377b43c8206340fd184167754f2c81dad5ab1" - integrity sha512-II8N/ky/Vpd8y7LTxwCuAYoQ8XeV3HYxuK7IDmyoFacIhDljx4sdt/+sOwqgXEweQyCHlbZSKSaK82upqNM4Hw== +kerberos@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/kerberos/-/kerberos-2.1.1.tgz#170fc64d1a23e8c6d6ae2736d01189e2a1dbe0f7" + integrity sha512-414s1G/qgK2T60cXnZsHbtRj8Ynjg0DBlQWeY99tkyqQ2e8vGgFHvxRdvjTlLHg/SxBA0zLQcGE6Pk6Dfq/BCA== dependencies: bindings "^1.5.0" node-addon-api "^6.1.0" @@ -404,12 +428,12 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.5, micromatch@^4.0.6: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mimic-response@^3.1.0: @@ -479,10 +503,10 @@ node-gyp-build@4.8.1, node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== -node-pty@1.1.0-beta11: - version "1.1.0-beta11" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta11.tgz#909d5dd8f9aa2a7857e7b632fd4d2d4768bdf69f" - integrity sha512-vTjF+VrvSCfPDILUkIT+YrG1Fdn06/eBRS2fc9a3JzYAvknMB1Ip8aoJhxl8hNpjWAbprmCEiV91mlfNpCD+GQ== +node-pty@1.1.0-beta21: + version "1.1.0-beta21" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta21.tgz#d75c1dfe4ff2c173459c974df72e91a4eae6dc52" + integrity sha512-FYpnY9g8qMQLTpqyeY9NVli6YfCWwvG6v6gmaDBbPjlc1VMp/+Zivq0SStDrRr1aciGnFCZzpL0BzdMnmbDnAw== dependencies: node-addon-api "^7.1.0" @@ -553,6 +577,11 @@ readable-stream@^3.1.1, readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -683,10 +712,10 @@ vscode-regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/vscode-regexpp/-/vscode-regexpp-3.1.0.tgz#42d059b6fffe99bd42939c0d013f632f0cad823f" integrity sha512-pqtN65VC1jRLawfluX4Y80MMG0DHJydWhe5ZwMHewZD6sys4LbU6lHwFAHxeuaVE6Y6+xZOtAw+9hvq7/0ejkg== -vscode-textmate@9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c" - integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg== +vscode-textmate@9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.1.0.tgz#656a6aa163a9578397ba810733952bedb2b47202" + integrity sha512-lxKSVp2DkFOx9RDAvpiYUrB9/KT1fAfi1aE8CBGstP8N7rLF+Seifj8kDA198X0mYj1CjQUC+81+nQf8CO0nVA== wrappy@1: version "1.0.2" diff --git a/resources/linux/debian/postinst.template b/resources/linux/debian/postinst.template index 16acb1481bf..81b75d97c67 100755 --- a/resources/linux/debian/postinst.template +++ b/resources/linux/debian/postinst.template @@ -22,6 +22,12 @@ if hash update-mime-database 2>/dev/null; then update-mime-database /usr/share/mime fi +# --- Start Positron --- +# Skip the rest of this file; it attempts to register Microsoft repositories +# which aren't needed for Positron. +exit 0 +# --- End Positron --- + if [ "@@NAME@@" != "code-oss" ]; then # Remove the legacy bin command if this is the stable build if [ "@@NAME@@" = "code" ]; then @@ -31,24 +37,54 @@ if [ "@@NAME@@" != "code-oss" ]; then # Register apt repository eval $(apt-config shell APT_SOURCE_PARTS Dir::Etc::sourceparts/d) CODE_SOURCE_PART=${APT_SOURCE_PARTS}vscode.list + CODE_SOURCE_PART_DEB822=${APT_SOURCE_PARTS}vscode.sources eval $(apt-config shell APT_TRUSTED_PARTS Dir::Etc::trustedparts/d) CODE_TRUSTED_PART=${APT_TRUSTED_PARTS}microsoft.gpg - # Install repository source list + RET=true + if [ -e '/usr/share/debconf/confmodule' ]; then + . /usr/share/debconf/confmodule + db_get @@NAME@@/add-microsoft-repo || true + fi + + # Determine whether to install the repository source list WRITE_SOURCE=0 - if [ ! -f $CODE_SOURCE_PART ] && [ ! -f /etc/rpi-issue ]; then - # Write source list if it does not exist and we're not running on Raspberry Pi OS - WRITE_SOURCE=1 - elif grep -Eq "http:\/\/packages\.microsoft\.com\/repos\/vscode" $CODE_SOURCE_PART; then + if [ "$RET" = false ]; then + # The user does not want to add the Microsoft repository + WRITE_SOURCE=0 + elif [ -f "$CODE_SOURCE_PART_DEB822" ]; then + # The user has migrated themselves to the DEB822 format + WRITE_SOURCE=0 + elif [ -f "$CODE_SOURCE_PART" ] && (grep -q "http://packages.microsoft.com/repos/vscode" $CODE_SOURCE_PART); then + # Migrate from old repository + WRITE_SOURCE=2 + elif [ -f "$CODE_SOURCE_PART" ] && (grep -q "http://packages.microsoft.com/repos/code" $CODE_SOURCE_PART); then # Migrate from old repository + WRITE_SOURCE=2 + elif apt-cache policy | grep -q "https://packages.microsoft.com/repos/code"; then + # The user is already on the new repository + WRITE_SOURCE=0 + elif [ ! -f $CODE_SOURCE_PART ] && [ ! -f /etc/rpi-issue ]; then + # Write source list if it does not exist and we're not running on Raspberry Pi OS WRITE_SOURCE=1 elif grep -q "# disabled on upgrade to" $CODE_SOURCE_PART; then # Write source list if it was disabled by OS upgrade WRITE_SOURCE=1 fi - if [ "$WRITE_SOURCE" -eq "1" ]; then + if [ "$WRITE_SOURCE" -eq "1" ] && [ -e '/usr/share/debconf/confmodule' ]; then + # Ask the user whether to actually write the source list + db_input high @@NAME@@/add-microsoft-repo || true + db_go || true + + db_get @@NAME@@/add-microsoft-repo + if [ "$RET" = false ]; then + WRITE_SOURCE=0 + fi + fi + + if [ "$WRITE_SOURCE" -ne "0" ]; then echo "### THIS FILE IS AUTOMATICALLY CONFIGURED ### # You may comment out this entry, but any other modifications may be lost. deb [arch=amd64,arm64,armhf] https://packages.microsoft.com/repos/code stable main" > $CODE_SOURCE_PART diff --git a/resources/linux/debian/postrm.template b/resources/linux/debian/postrm.template index fb36d522f38..dcbfda95ea0 100755 --- a/resources/linux/debian/postrm.template +++ b/resources/linux/debian/postrm.template @@ -14,3 +14,22 @@ fi if hash update-mime-database 2>/dev/null; then update-mime-database /usr/share/mime fi + +RET=true +if [ -e '/usr/share/debconf/confmodule' ]; then + . /usr/share/debconf/confmodule + db_get @@NAME@@/add-microsoft-repo || true +fi +if [ "$RET" = "true" ]; then + eval $(apt-config shell APT_SOURCE_PARTS Dir::Etc::sourceparts/d) + CODE_SOURCE_PART=${APT_SOURCE_PARTS}vscode.list + rm -f $CODE_SOURCE_PART + + eval $(apt-config shell APT_TRUSTED_PARTS Dir::Etc::trustedparts/d) + CODE_TRUSTED_PART=${APT_TRUSTED_PARTS}microsoft.gpg + rm -f $CODE_TRUSTED_PART +fi + +if [ "$1" = "purge" ] && [ -e '/usr/share/debconf/confmodule' ]; then + db_purge +fi diff --git a/resources/linux/debian/templates.template b/resources/linux/debian/templates.template new file mode 100644 index 00000000000..7be5e039b26 --- /dev/null +++ b/resources/linux/debian/templates.template @@ -0,0 +1,6 @@ +Template: @@NAME@@/add-microsoft-repo +Type: boolean +Default: true +Description: Add Microsoft apt repository for Visual Studio Code? + The installer would like to add the Microsoft repository and signing + key to update VS Code through apt. diff --git a/scripts/code-web.js b/scripts/code-web.js index 467f147d027..42fa65aaa4c 100644 --- a/scripts/code-web.js +++ b/scripts/code-web.js @@ -74,6 +74,10 @@ async function main() { openSystemBrowser = true; } + if (fs.existsSync(path.join(APP_ROOT, 'src2')) || fs.existsSync(path.join(APP_ROOT, 'out-build', 'esm'))) { + serverArgs.push('--esm'); + } + serverArgs.push('--sourcesPath', APP_ROOT); serverArgs.push(...process.argv.slice(2).filter(v => !v.startsWith('--playground') && v !== '--no-playground')); diff --git a/scripts/test-esm.bat b/scripts/test-esm.bat new file mode 100644 index 00000000000..faeff79007b --- /dev/null +++ b/scripts/test-esm.bat @@ -0,0 +1,31 @@ +@echo off +setlocal + +set ELECTRON_RUN_AS_NODE= + +pushd %~dp0\.. + +:: Get Code.exe location +for /f "tokens=2 delims=:," %%a in ('findstr /R /C:"\"nameShort\":.*" product.json') do set NAMESHORT=%%~a +set NAMESHORT=%NAMESHORT: "=% +set NAMESHORT=%NAMESHORT:"=%.exe +set CODE=".build\electron\%NAMESHORT%" + +:: Download Electron if needed +call node build\lib\electron.js +if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron + +:: Run tests +set ELECTRON_ENABLE_LOGGING=1 +%CODE% .\test\unit\electron\index.esm.js --crash-reporter-directory=%~dp0\..\.build\crashes %* + +popd + +endlocal + +:: app.exit(0) is exiting with code 255 in Electron 1.7.4. +:: See https://github.com/microsoft/vscode/issues/28582 +echo errorlevel: %errorlevel% +if %errorlevel% == 255 set errorlevel=0 + +exit /b %errorlevel% diff --git a/scripts/test-esm.sh b/scripts/test-esm.sh new file mode 100755 index 00000000000..ddb619017a6 --- /dev/null +++ b/scripts/test-esm.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -e + +if [[ "$OSTYPE" == "darwin"* ]]; then + realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } + ROOT=$(dirname $(dirname $(realpath "$0"))) +else + ROOT=$(dirname $(dirname $(readlink -f $0))) + # --disable-dev-shm-usage: when run on docker containers where size of /dev/shm + # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory + LINUX_EXTRA_ARGS="--disable-dev-shm-usage" +fi + +cd $ROOT + +if [[ "$OSTYPE" == "darwin"* ]]; then + NAME=`node -p "require('./product.json').nameLong"` + CODE="./.build/electron/$NAME.app/Contents/MacOS/Electron" +else + NAME=`node -p "require('./product.json').applicationName"` + CODE=".build/electron/$NAME" +fi + +VSCODECRASHDIR=$ROOT/.build/crashes + +# Node modules +test -d node_modules || yarn + +# Get electron +yarn electron + +# Unit Tests +if [[ "$OSTYPE" == "darwin"* ]]; then + cd $ROOT ; ulimit -n 4096 ; \ + ELECTRON_ENABLE_LOGGING=1 \ + "$CODE" \ + test/unit/electron/index.esm.js --crash-reporter-directory=$VSCODECRASHDIR "$@" +else + cd $ROOT ; \ + ELECTRON_ENABLE_LOGGING=1 \ + "$CODE" \ + test/unit/electron/index.esm.js --crash-reporter-directory=$VSCODECRASHDIR $LINUX_EXTRA_ARGS "$@" +fi diff --git a/scripts/test-integration-esm.bat b/scripts/test-integration-esm.bat new file mode 100644 index 00000000000..0d12b225179 --- /dev/null +++ b/scripts/test-integration-esm.bat @@ -0,0 +1,119 @@ +@echo off +setlocal + +pushd %~dp0\.. + +set VSCODEUSERDATADIR=%TEMP%\vscodeuserfolder-%RANDOM%-%TIME:~6,2% +set VSCODECRASHDIR=%~dp0\..\.build\crashes +set VSCODELOGSDIR=%~dp0\..\.build\logs\integration-tests + +:: Figure out which Electron to use for running tests +if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( + chcp 65001 + set INTEGRATION_TEST_ELECTRON_PATH=.\scripts\code.bat + set VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE=1 + + echo Running integration tests out of sources. +) else ( + set VSCODE_CLI=1 + set ELECTRON_ENABLE_LOGGING=1 + + echo Running integration tests with '%INTEGRATION_TEST_ELECTRON_PATH%' as build. +) + +echo Storing crash reports into '%VSCODECRASHDIR%'. +echo Storing log files into '%VSCODELOGSDIR%'. + + +:: Tests standalone (AMD) + +echo. +echo ### node.js integration tests +call .\scripts\test-esm.bat --runGlob **\*.integrationTest.js %* +if %errorlevel% neq 0 exit /b %errorlevel% + + +:: Tests in the extension host + +set API_TESTS_EXTRA_ARGS=--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=%VSCODECRASHDIR% --logsPath=%VSCODELOGSDIR% --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=%VSCODEUSERDATADIR% + +echo. +echo ### API tests (folder) +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests %API_TESTS_EXTRA_ARGS% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### API tests (workspace) +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests %API_TESTS_EXTRA_ARGS% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Colorize tests +call yarn test-extension -l vscode-colorize-tests +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### TypeScript tests +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\typescript-language-features\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\typescript-language-features --extensionTestsPath=%~dp0\..\extensions\typescript-language-features\out\test\unit %API_TESTS_EXTRA_ARGS% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Markdown tests +call yarn test-extension -l markdown-language-features +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Emmet tests +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\emmet\test-workspace --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test %API_TESTS_EXTRA_ARGS% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Git tests +for /f "delims=" %%i in ('node -p "require('fs').realpathSync.native(require('os').tmpdir())"') do set TEMPDIR=%%i +set GITWORKSPACE=%TEMPDIR%\git-%RANDOM% +mkdir %GITWORKSPACE% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %GITWORKSPACE% --extensionDevelopmentPath=%~dp0\..\extensions\git --extensionTestsPath=%~dp0\..\extensions\git\out\test %API_TESTS_EXTRA_ARGS% +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Ipynb tests +call yarn test-extension -l ipynb +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Notebook Output tests +call yarn test-extension -l notebook-renderers +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### Configuration editing tests +set CFWORKSPACE=%TEMPDIR%\cf-%RANDOM% +mkdir %CFWORKSPACE% +call yarn test-extension -l configuration-editing +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### GitHub Authentication tests +call yarn test-extension -l github-authentication +if %errorlevel% neq 0 exit /b %errorlevel% + +:: Tests standalone (CommonJS) + +echo. +echo ### CSS tests +call %~dp0\node-electron.bat %~dp0\..\extensions\css-language-features/server/test/index.js +if %errorlevel% neq 0 exit /b %errorlevel% + +echo. +echo ### HTML tests +call %~dp0\node-electron.bat %~dp0\..\extensions\html-language-features/server/test/index.js +if %errorlevel% neq 0 exit /b %errorlevel% + + +:: Cleanup + +rmdir /s /q %VSCODEUSERDATADIR% + +popd + +endlocal diff --git a/scripts/test-integration-esm.sh b/scripts/test-integration-esm.sh new file mode 100755 index 00000000000..dde3bc0520d --- /dev/null +++ b/scripts/test-integration-esm.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -e + +if [[ "$OSTYPE" == "darwin"* ]]; then + realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } + ROOT=$(dirname $(dirname $(realpath "$0"))) +else + ROOT=$(dirname $(dirname $(readlink -f $0))) + # --disable-dev-shm-usage: when run on docker containers where size of /dev/shm + # partition < 64MB which causes OOM failure for chromium compositor that uses the partition for shared memory + LINUX_EXTRA_ARGS="--disable-dev-shm-usage" +fi + +VSCODEUSERDATADIR=`mktemp -d 2>/dev/null` +VSCODECRASHDIR=$ROOT/.build/crashes +VSCODELOGSDIR=$ROOT/.build/logs/integration-tests + +cd $ROOT + +# Figure out which Electron to use for running tests +if [ -z "$INTEGRATION_TEST_ELECTRON_PATH" ] +then + INTEGRATION_TEST_ELECTRON_PATH="./scripts/code.sh" + + echo "Running integration tests out of sources." +else + export VSCODE_CLI=1 + export ELECTRON_ENABLE_LOGGING=1 + + echo "Running integration tests with '$INTEGRATION_TEST_ELECTRON_PATH' as build." +fi + +echo "Storing crash reports into '$VSCODECRASHDIR'." +echo "Storing log files into '$VSCODELOGSDIR'." + + +# Tests standalone (AMD) + +echo +echo "### node.js integration tests" +echo +./scripts/test-esm.sh --runGlob **/*.integrationTest.js "$@" + + +# Tests in the extension host + +API_TESTS_EXTRA_ARGS="--disable-telemetry --skip-welcome --skip-release-notes --crash-reporter-directory=$VSCODECRASHDIR --logsPath=$VSCODELOGSDIR --no-cached-data --disable-updates --use-inmemory-secretstorage --disable-extensions --disable-workspace-trust --user-data-dir=$VSCODEUSERDATADIR" + +if [ -z "$INTEGRATION_TEST_APP_NAME" ]; then + kill_app() { true; } +else + kill_app() { killall $INTEGRATION_TEST_APP_NAME || true; } +fi + +echo +echo "### API tests (folder)" +echo +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests $API_TESTS_EXTRA_ARGS +kill_app + +echo +echo "### API tests (workspace)" +echo +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests $API_TESTS_EXTRA_ARGS +kill_app + +echo +echo "### Colorize tests" +echo +yarn test-extension -l vscode-colorize-tests +kill_app + +echo +echo "### TypeScript tests" +echo +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/typescript-language-features/test-workspace --extensionDevelopmentPath=$ROOT/extensions/typescript-language-features --extensionTestsPath=$ROOT/extensions/typescript-language-features/out/test/unit $API_TESTS_EXTRA_ARGS +kill_app + +echo +echo "### Markdown tests" +echo +yarn test-extension -l markdown-language-features +kill_app + +echo +echo "### Emmet tests" +echo +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $ROOT/extensions/emmet/test-workspace --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test $API_TESTS_EXTRA_ARGS +kill_app + +echo +echo "### Git tests" +echo +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_EXTRA_ARGS $(mktemp -d 2>/dev/null) --extensionDevelopmentPath=$ROOT/extensions/git --extensionTestsPath=$ROOT/extensions/git/out/test $API_TESTS_EXTRA_ARGS +kill_app + +echo +echo "### Ipynb tests" +echo +yarn test-extension -l ipynb +kill_app + +echo +echo "### Notebook Output tests" +echo +yarn test-extension -l notebook-renderers +kill_app + +echo +echo "### Configuration editing tests" +echo +yarn test-extension -l configuration-editing +kill_app + +echo +echo "### GitHub Authentication tests" +echo +yarn test-extension -l github-authentication +kill_app + +# Tests standalone (CommonJS) + +echo +echo "### CSS tests" +echo +cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js + +echo +echo "### HTML tests" +echo +cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js + + +# Cleanup + +rm -rf $VSCODEUSERDATADIR diff --git a/scripts/xterm-update.ps1 b/scripts/xterm-update.ps1 index 11c282de888..2eae7fffe77 100644 --- a/scripts/xterm-update.ps1 +++ b/scripts/xterm-update.ps1 @@ -1 +1,2 @@ -node $PSScriptRoot\xterm-update.js (Get-Location) +$scriptPath = Join-Path $PSScriptRoot "xterm-update.js" +node $scriptPath (Get-Location) diff --git a/src/bootstrap-amd.js b/src/bootstrap-amd.js index 27b389cbdd1..5a4aa435c8e 100644 --- a/src/bootstrap-amd.js +++ b/src/bootstrap-amd.js @@ -11,22 +11,38 @@ * @import { IProductConfiguration } from './vs/base/common/product' */ -// ESM-comment-begin -const isESM = false; -// ESM-comment-end // ESM-uncomment-begin // import * as path from 'path'; // import * as fs from 'fs'; // import { fileURLToPath } from 'url'; -// import { createRequire } from 'node:module'; +// import { createRequire, register } from 'node:module'; // import { product, pkg } from './bootstrap-meta.js'; -// import * as bootstrap from './bootstrap.js'; +// import './bootstrap-node.js'; // import * as performance from './vs/base/common/performance.js'; // // const require = createRequire(import.meta.url); -// const isESM = true; +// /** @type any */ // const module = { exports: {} }; // const __dirname = path.dirname(fileURLToPath(import.meta.url)); +// +// // Install a hook to module resolution to map 'fs' to 'original-fs' +// if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { +// const jsCode = ` +// export async function resolve(specifier, context, nextResolve) { +// if (specifier === 'fs') { +// return { +// format: 'builtin', +// shortCircuit: true, +// url: 'node:original-fs' +// }; +// } + +// // Defer to the next hook in the chain, which would be the +// // Node.js default resolve if this is the last user-specified loader. +// return nextResolve(specifier, context); +// }`; +// register(`data:text/javascript;base64,${Buffer.from(jsCode).toString('base64')}`, import.meta.url); +// } // ESM-uncomment-end // Store the node.js require function in a variable @@ -78,7 +94,7 @@ globalThis.acquirePositronApi = function () { globalThis._VSCODE_FILE_ROOT = __dirname; // ESM-comment-begin -const bootstrap = require('./bootstrap'); +const bootstrapNode = require('./bootstrap-node'); const performance = require(`./vs/base/common/performance`); const fs = require('fs'); // ESM-comment-end @@ -120,7 +136,6 @@ async function doSetupNLS() { messagesFile = nlsConfig.defaultMessagesFile; } - // VSCODE_GLOBALS: NLS globalThis._VSCODE_NLS_LANGUAGE = nlsConfig?.resolvedLanguage; } catch (e) { console.error(`Error reading VSCODE_NLS_CONFIG from environment: ${e}`); @@ -135,7 +150,6 @@ async function doSetupNLS() { } try { - // VSCODE_GLOBALS: NLS globalThis._VSCODE_NLS_MESSAGES = JSON.parse((await fs.promises.readFile(messagesFile)).toString()); } catch (error) { console.error(`Error reading NLS messages file ${messagesFile}: ${error}`); @@ -152,7 +166,6 @@ async function doSetupNLS() { // Fallback to the default message file to ensure english translation at least if (nlsConfig?.defaultMessagesFile && nlsConfig.defaultMessagesFile !== messagesFile) { try { - // VSCODE_GLOBALS: NLS globalThis._VSCODE_NLS_MESSAGES = JSON.parse((await fs.promises.readFile(nlsConfig.defaultMessagesFile)).toString()); } catch (error) { console.error(`Error reading default NLS messages file ${nlsConfig.defaultMessagesFile}: ${error}`); @@ -169,77 +182,77 @@ async function doSetupNLS() { //#region Loader Config -if (isESM) { - - /** - * @param {string=} entrypoint - * @param {(value: any) => void} [onLoad] - * @param {(err: Error) => void} [onError] - */ - module.exports.load = function (entrypoint, onLoad, onError) { - if (!entrypoint) { - return; - } - - entrypoint = `./${entrypoint}.js`; - - onLoad = onLoad || function () { }; - onError = onError || function (err) { console.error(err); }; +// ESM-uncomment-begin +// /** +// * @param {string=} entrypoint +// * @param {(value: any) => void} [onLoad] +// * @param {(err: Error) => void} [onError] +// */ +// module.exports.load = function (entrypoint, onLoad, onError) { +// if (!entrypoint) { +// return; +// } + +// entrypoint = `./${entrypoint}.js`; + +// onLoad = onLoad || function () { }; +// onError = onError || function (err) { console.error(err); }; + +// setupNLS().then(() => { +// performance.mark(`code/fork/willLoadCode`); +// import(entrypoint).then(onLoad, onError); +// }); +// }; +// ESM-uncomment-end - setupNLS().then(() => { - performance.mark(`code/fork/willLoadCode`); - import(entrypoint).then(onLoad, onError); - }); - }; -} else { - - // @ts-ignore - const loader = require('./vs/loader'); - - loader.config({ - baseUrl: bootstrap.fileUriFromPath(__dirname, { isWindows: process.platform === 'win32' }), - catchError: true, - nodeRequire, - amdModulesPattern: /^vs\//, - recordStats: true +// ESM-comment-begin +// @ts-ignore +const loader = require('./vs/loader'); + +loader.config({ + baseUrl: bootstrapNode.fileUriFromPath(__dirname, { isWindows: process.platform === 'win32' }), + catchError: true, + nodeRequire, + amdModulesPattern: /^vs\//, + recordStats: true +}); + +// Running in Electron +if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { + loader.define('fs', ['original-fs'], function (/** @type {import('fs')} */originalFS) { + return originalFS; // replace the patched electron fs with the original node fs for all AMD code }); +} - // Running in Electron - if (process.env['ELECTRON_RUN_AS_NODE'] || process.versions['electron']) { - loader.define('fs', ['original-fs'], function (/** @type {import('fs')} */originalFS) { - return originalFS; // replace the patched electron fs with the original node fs for all AMD code - }); +/** + * @param {string=} entrypoint + * @param {(value: any) => void} [onLoad] + * @param {(err: Error) => void} [onError] + */ +module.exports.load = function (entrypoint, onLoad, onError) { + if (!entrypoint) { + return; } - /** - * @param {string=} entrypoint - * @param {(value: any) => void} [onLoad] - * @param {(err: Error) => void} [onError] - */ - module.exports.load = function (entrypoint, onLoad, onError) { - if (!entrypoint) { - return; - } - - // code cache config - if (process.env['VSCODE_CODE_CACHE_PATH']) { - loader.config({ - nodeCachedData: { - path: process.env['VSCODE_CODE_CACHE_PATH'], - seed: entrypoint - } - }); - } + // code cache config + if (process.env['VSCODE_CODE_CACHE_PATH']) { + loader.config({ + nodeCachedData: { + path: process.env['VSCODE_CODE_CACHE_PATH'], + seed: entrypoint + } + }); + } - onLoad = onLoad || function () { }; - onError = onError || function (err) { console.error(err); }; + onLoad = onLoad || function () { }; + onError = onError || function (err) { console.error(err); }; - setupNLS().then(() => { - performance.mark('code/fork/willLoadCode'); - loader([entrypoint], onLoad, onError); - }); - }; -} + setupNLS().then(() => { + performance.mark('code/fork/willLoadCode'); + loader([entrypoint], onLoad, onError); + }); +}; +// ESM-comment-end //#endregion diff --git a/src/bootstrap-cli.js b/src/bootstrap-cli.js new file mode 100644 index 00000000000..8f077a0eeaf --- /dev/null +++ b/src/bootstrap-cli.js @@ -0,0 +1,14 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check +'use strict'; + +// Delete `VSCODE_CWD` very early. We have seen +// reports where `code .` would use the wrong +// current working directory due to our variable +// somehow escaping to the parent shell +// (https://github.com/microsoft/vscode/issues/126399) +delete process.env['VSCODE_CWD']; diff --git a/src/bootstrap-fork.js b/src/bootstrap-fork.js index a95cbf53589..e1826549726 100644 --- a/src/bootstrap-fork.js +++ b/src/bootstrap-fork.js @@ -8,13 +8,11 @@ // ESM-comment-begin const performance = require('./vs/base/common/performance'); -const bootstrap = require('./bootstrap'); const bootstrapNode = require('./bootstrap-node'); const bootstrapAmd = require('./bootstrap-amd'); // ESM-comment-end // ESM-uncomment-begin // import * as performance from './vs/base/common/performance.js'; -// import * as bootstrap from './bootstrap.js'; // import * as bootstrapNode from './bootstrap-node.js'; // import * as bootstrapAmd from './bootstrap-amd.js'; // ESM-uncomment-end @@ -24,14 +22,14 @@ performance.mark('code/fork/start'); // Crash reporter configureCrashReporter(); -// Remove global paths from the node module lookup -bootstrapNode.removeGlobalNodeModuleLookupPaths(); +// Remove global paths from the node module lookup (node.js only) +bootstrapNode.removeGlobalNodeJsModuleLookupPaths(); // Enable ASAR in our forked processes -bootstrap.enableASARSupport(); +bootstrapNode.enableASARSupport(); -if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) { - bootstrapNode.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']); +if (process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']) { + bootstrapNode.devInjectNodeModuleLookupPath(process.env['VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATH']); } // Configure: pipe logging to parent process diff --git a/src/bootstrap-import.js b/src/bootstrap-import.js new file mode 100644 index 00000000000..070b0b93b4b --- /dev/null +++ b/src/bootstrap-import.js @@ -0,0 +1,78 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +// ********************************************************************* +// * * +// * We need this to redirect to node_modules from the remote-folder. * +// * This ONLY applies when running out of source. * +// * * +// ********************************************************************* + +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { promises } from 'node:fs'; +import { join } from 'node:path'; + +// SEE https://nodejs.org/docs/latest/api/module.html#initialize + +/** + * @type {Object.} + */ +const _specifierToUrl = {}; + +/** + * @param {string} injectPath + */ +export async function initialize(injectPath) { + // populate mappings + + const injectPackageJSONPath = fileURLToPath(new URL('../package.json', pathToFileURL(injectPath))); + const packageJSON = JSON.parse(String(await promises.readFile(injectPackageJSONPath))); + + for (const [name] of Object.entries(packageJSON.dependencies)) { + try { + const path = join(injectPackageJSONPath, `../node_modules/${name}/package.json`); + let { main } = JSON.parse(String(await promises.readFile(path))); + + if (!main) { + main = 'index.js'; + } + if (!main.endsWith('.js')) { + main += '.js'; + } + const mainPath = join(injectPackageJSONPath, `../node_modules/${name}/${main}`); + _specifierToUrl[name] = pathToFileURL(mainPath).href; + + } catch (err) { + console.error(name); + console.error(err); + } + } + + console.log(`[bootstrap-import] Initialized node_modules redirector for: ${injectPath}`); +} + +/** + * @param {string | number} specifier + * @param {any} context + * @param {(arg0: any, arg1: any) => any} nextResolve + */ +export async function resolve(specifier, context, nextResolve) { + + const newSpecifier = _specifierToUrl[specifier]; + if (newSpecifier !== undefined) { + // console.log('[HOOKS]', specifier, '--->', newSpecifier); + return { + format: 'commonjs', + shortCircuit: true, + url: newSpecifier + }; + } + + // Defer to the next hook in the chain, which would be the + // Node.js default resolve if this is the last user-specified loader. + return nextResolve(specifier, context); +} diff --git a/src/bootstrap-meta.js b/src/bootstrap-meta.js index 5415bc5df6a..b437ed75c20 100644 --- a/src/bootstrap-meta.js +++ b/src/bootstrap-meta.js @@ -14,6 +14,7 @@ // import { createRequire } from 'node:module'; // // const require = createRequire(import.meta.url); +// /** @type any */ // const module = { exports: {} }; // ESM-uncomment-end diff --git a/src/bootstrap-node.js b/src/bootstrap-node.js index 4a829557f0d..8c9af7d924e 100644 --- a/src/bootstrap-node.js +++ b/src/bootstrap-node.js @@ -9,8 +9,7 @@ // ESM-comment-begin const path = require('path'); const fs = require('fs'); - -const isESM = false; +const Module = require('module'); // ESM-comment-end // ESM-uncomment-begin // import * as path from 'path'; @@ -19,11 +18,29 @@ const isESM = false; // import { createRequire } from 'node:module'; // // const require = createRequire(import.meta.url); -// const isESM = true; +// /** @type any */ // const module = { exports: {} }; // const __dirname = path.dirname(fileURLToPath(import.meta.url)); // ESM-uncomment-end +// increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) +Error.stackTraceLimit = 100; + +if (!process.env['VSCODE_HANDLES_SIGPIPE']) { + // Workaround for Electron not installing a handler to ignore SIGPIPE + // (https://github.com/electron/electron/issues/13254) + let didLogAboutSIGPIPE = false; + process.on('SIGPIPE', () => { + // See https://github.com/microsoft/vscode-remote-release/issues/6543 + // In certain situations, the console itself can be in a broken pipe state + // so logging SIGPIPE to the console will cause an infinite async loop + if (!didLogAboutSIGPIPE) { + didLogAboutSIGPIPE = true; + console.error(new Error(`Unexpected SIGPIPE`)); + } + }); +} + // Setup current working directory in all our node & electron processes // - Windows: call `process.chdir()` to always set application folder as cwd // - all OS: store the `process.cwd()` inside `VSCODE_CWD` for consistent lookups @@ -52,43 +69,52 @@ setupCurrentWorkingDirectory(); /** * Add support for redirecting the loading of node modules * + * Note: only applies when running out of sources. + * * @param {string} injectPath */ -module.exports.injectNodeModuleLookupPath = function (injectPath) { +module.exports.devInjectNodeModuleLookupPath = function (injectPath) { + if (!process.env['VSCODE_DEV']) { + return; // only applies running out of sources + } + if (!injectPath) { throw new Error('Missing injectPath'); } const Module = require('node:module'); - if (isESM) { - // register a loader hook - // ESM-uncomment-begin - // Module.register('./server-loader.mjs', { parentURL: import.meta.url, data: injectPath }); - // ESM-uncomment-end - } else { - const nodeModulesPath = path.join(__dirname, '../node_modules'); + // ESM-uncomment-begin + // // register a loader hook + // Module.register('./bootstrap-import.js', { parentURL: import.meta.url, data: injectPath }); + // ESM-uncomment-end + // ESM-comment-begin + const nodeModulesPath = path.join(__dirname, '../node_modules'); - // @ts-ignore - const originalResolveLookupPaths = Module._resolveLookupPaths; + // @ts-ignore + const originalResolveLookupPaths = Module._resolveLookupPaths; - // @ts-ignore - Module._resolveLookupPaths = function (moduleName, parent) { - const paths = originalResolveLookupPaths(moduleName, parent); - if (Array.isArray(paths)) { - for (let i = 0, len = paths.length; i < len; i++) { - if (paths[i] === nodeModulesPath) { - paths.splice(i, 0, injectPath); - break; - } + // @ts-ignore + Module._resolveLookupPaths = function (moduleName, parent) { + const paths = originalResolveLookupPaths(moduleName, parent); + if (Array.isArray(paths)) { + for (let i = 0, len = paths.length; i < len; i++) { + if (paths[i] === nodeModulesPath) { + paths.splice(i, 0, injectPath); + break; } } + } - return paths; - }; - } + return paths; + }; + // ESM-comment-end }; -module.exports.removeGlobalNodeModuleLookupPaths = function () { +module.exports.removeGlobalNodeJsModuleLookupPaths = function () { + if (typeof process?.versions?.electron === 'string') { + return; // Electron disables global search paths in https://github.com/electron/electron/blob/3186c2f0efa92d275dc3d57b5a14a60ed3846b0e/shell/common/node_bindings.cc#L653 + } + const Module = require('module'); // @ts-ignore const globalPaths = Module.globalPaths; @@ -177,8 +203,76 @@ module.exports.configurePortable = function (product) { }; }; +/** + * Helper to enable ASAR support. + */ +module.exports.enableASARSupport = function () { + // ESM-comment-begin + const NODE_MODULES_PATH = path.join(__dirname, '../node_modules'); + const NODE_MODULES_ASAR_PATH = `${NODE_MODULES_PATH}.asar`; + + // @ts-ignore + const originalResolveLookupPaths = Module._resolveLookupPaths; + + // @ts-ignore + Module._resolveLookupPaths = function (request, parent) { + const paths = originalResolveLookupPaths(request, parent); + if (Array.isArray(paths)) { + for (let i = 0, len = paths.length; i < len; i++) { + if (paths[i] === NODE_MODULES_PATH) { + paths.splice(i, 0, NODE_MODULES_ASAR_PATH); + break; + } + } + } + + return paths; + }; + // ESM-comment-end +}; + +/** + * Helper to convert a file path to a URI. + * + * TODO@bpasero TODO@esm check for removal once ESM has landed. + * + * @param {string} path + * @param {{ isWindows?: boolean, scheme?: string, fallbackAuthority?: string }} config + * @returns {string} + */ +module.exports.fileUriFromPath = function (path, config) { + + // Since we are building a URI, we normalize any backslash + // to slashes and we ensure that the path begins with a '/'. + let pathName = path.replace(/\\/g, '/'); + if (pathName.length > 0 && pathName.charAt(0) !== '/') { + pathName = `/${pathName}`; + } + + /** @type {string} */ + let uri; + + // Windows: in order to support UNC paths (which start with '//') + // that have their own authority, we do not use the provided authority + // but rather preserve it. + if (config.isWindows && pathName.startsWith('//')) { + uri = encodeURI(`${config.scheme || 'file'}:${pathName}`); + } + + // Otherwise we optionally add the provided authority if specified + else { + uri = encodeURI(`${config.scheme || 'file'}://${config.fallbackAuthority || ''}${pathName}`); + } + + return uri.replace(/#/g, '%23'); +}; + +//#endregion + // ESM-uncomment-begin -// export const injectNodeModuleLookupPath = module.exports.injectNodeModuleLookupPath; -// export const removeGlobalNodeModuleLookupPaths = module.exports.removeGlobalNodeModuleLookupPaths; +// export const devInjectNodeModuleLookupPath = module.exports.devInjectNodeModuleLookupPath; +// export const removeGlobalNodeJsModuleLookupPaths = module.exports.removeGlobalNodeJsModuleLookupPaths; // export const configurePortable = module.exports.configurePortable; +// export const enableASARSupport = module.exports.enableASARSupport; +// export const fileUriFromPath = module.exports.fileUriFromPath; // ESM-uncomment-end diff --git a/src/bootstrap-server.js b/src/bootstrap-server.js new file mode 100644 index 00000000000..b84cc6a6ef6 --- /dev/null +++ b/src/bootstrap-server.js @@ -0,0 +1,10 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check +'use strict'; + +// Keep bootstrap-amd.js from redefining 'fs'. +delete process.env['ELECTRON_RUN_AS_NODE']; diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index f5fe712fb29..a176820a273 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -13,33 +13,18 @@ * @typedef {any} LoaderConfig */ -/* eslint-disable no-restricted-globals, */ +/* eslint-disable no-restricted-globals */ -// ESM-comment-begin -const isESM = false; -// ESM-comment-end -// ESM-uncomment-begin -// const isESM = true; -// ESM-uncomment-end - -// Simple module style to support node.js and browser environments (function (factory) { - - // Node.js - if (typeof exports === 'object') { - module.exports = factory(); - } - - // Browser - else { - // @ts-ignore - globalThis.MonacoBootstrapWindow = factory(); - } + // @ts-ignore + globalThis.MonacoBootstrapWindow = factory(); }(function () { - const bootstrapLib = bootstrap(); const preloadGlobals = sandboxGlobals(); const safeProcess = preloadGlobals.process; + // increase number of stack frames(from 10, https://github.com/v8/v8/wiki/Stack-Trace-API) + Error.stackTraceLimit = 100; + /** * @param {string[]} modulePaths * @param {(result: unknown, configuration: ISandboxConfiguration) => Promise | undefined} resultCallback @@ -90,7 +75,6 @@ const isESM = false; developerDeveloperKeybindingsDisposable = registerDeveloperKeybindings(disallowReloadKeybinding); } - // VSCODE_GLOBALS: NLS globalThis._VSCODE_NLS_MESSAGES = configuration.nls.messages; globalThis._VSCODE_NLS_LANGUAGE = configuration.nls.language; let language = configuration.nls.language || 'en'; @@ -104,146 +88,146 @@ const isESM = false; window['MonacoEnvironment'] = {}; - if (isESM) { - - // Signal before require() - if (typeof options?.beforeRequire === 'function') { - options.beforeRequire(configuration); - } - - const fileRoot = `${configuration.appRoot}/out`; - globalThis._VSCODE_FILE_ROOT = fileRoot; - - // DEV --------------------------------------------------------------------------------------- - // DEV: This is for development and enables loading CSS via import-statements via import-maps. - // DEV: For each CSS modules that we have we defined an entry in the import map that maps to - // DEV: a blob URL that loads the CSS via a dynamic @import-rule. - // DEV --------------------------------------------------------------------------------------- - if (configuration.cssModules) { - performance.mark('code/willAddCssLoader'); - - const style = document.createElement('style'); - style.type = 'text/css'; - style.media = 'screen'; - style.id = 'vscode-css-loading'; - document.head.appendChild(style); - - globalThis._VSCODE_CSS_LOAD = function (url) { - style.textContent += `@import url(${url});\n`; - }; - - const baseUrl = new URL(`vscode-file://vscode-app${fileRoot}/`); - /** - * @type { { imports: Record }} - */ - const importMap = { imports: {} }; - for (const cssModule of configuration.cssModules) { - const cssUrl = new URL(cssModule, baseUrl).href; - const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`; - const blob = new Blob([jsSrc], { type: 'application/javascript' }); - importMap.imports[cssUrl] = URL.createObjectURL(blob); - } - - const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, }); - const importMapSrc = JSON.stringify(importMap, undefined, 2); - const importMapScript = document.createElement('script'); - importMapScript.type = 'importmap'; - importMapScript.setAttribute('nonce', '0c6a828f1297'); - // @ts-ignore - importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc; - document.head.appendChild(importMapScript); - - performance.mark('code/didAddCssLoader'); - } - - const result = Promise.all(modulePaths.map(modulePath => { - if (modulePath.includes('vs/css!')) { - // ESM/CSS when seeing the old `vs/css!` prefix we use that as a signal to - // load CSS via a tag - const cssModule = modulePath.replace('vs/css!', ''); - const link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = `${configuration.appRoot}/out/${cssModule}.css`; - document.head.appendChild(link); - return Promise.resolve(); - - } else { - // ESM/JS module loading - return import(`${configuration.appRoot}/out/${modulePath}.js`); - } - })); - - result.then((res) => invokeResult(res[0]), onUnexpectedError); - } else { - - /** @type {LoaderConfig} */ - const loaderConfig = { - baseUrl: `${bootstrapLib.fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out`, - preferScriptTags: true - }; + // ESM-uncomment-begin + // // Signal before require() + // if (typeof options?.beforeRequire === 'function') { + // options.beforeRequire(configuration); + // } + + // const baseUrl = new URL(`${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out/`); + // globalThis._VSCODE_FILE_ROOT = baseUrl.toString(); + + // // DEV --------------------------------------------------------------------------------------- + // // DEV: This is for development and enables loading CSS via import-statements via import-maps. + // // DEV: For each CSS modules that we have we defined an entry in the import map that maps to + // // DEV: a blob URL that loads the CSS via a dynamic @import-rule. + // // DEV --------------------------------------------------------------------------------------- + // if (Array.isArray(configuration.cssModules) && configuration.cssModules.length > 0) { + // performance.mark('code/willAddCssLoader'); + + // const style = document.createElement('style'); + // style.type = 'text/css'; + // style.media = 'screen'; + // style.id = 'vscode-css-loading'; + // document.head.appendChild(style); + + // globalThis._VSCODE_CSS_LOAD = function (url) { + // style.textContent += `@import url(${url});\n`; + // }; + + // /** + // * @type { { imports: Record }} + // */ + // const importMap = { imports: {} }; + // for (const cssModule of configuration.cssModules) { + // const cssUrl = new URL(cssModule, baseUrl).href; + // const jsSrc = `globalThis._VSCODE_CSS_LOAD('${cssUrl}');\n`; + // const blob = new Blob([jsSrc], { type: 'application/javascript' }); + // importMap.imports[cssUrl] = URL.createObjectURL(blob); + // } + + // const ttp = window.trustedTypes?.createPolicy('vscode-bootstrapImportMap', { createScript(value) { return value; }, }); + // const importMapSrc = JSON.stringify(importMap, undefined, 2); + // const importMapScript = document.createElement('script'); + // importMapScript.type = 'importmap'; + // importMapScript.setAttribute('nonce', '0c6a828f1297'); + // // @ts-ignore + // importMapScript.textContent = ttp?.createScript(importMapSrc) ?? importMapSrc; + // document.head.appendChild(importMapScript); + + // performance.mark('code/didAddCssLoader'); + // } + + // const result = Promise.all(modulePaths.map(modulePath => { + // if (modulePath.includes('vs/css!')) { + // // ESM/CSS when seeing the old `vs/css!` prefix we use that as a signal to + // // load CSS via a tag + // const cssModule = modulePath.replace('vs/css!', ''); + // const link = document.createElement('link'); + // link.rel = 'stylesheet'; + // link.href = new URL(`${cssModule}.css`, baseUrl).href; + // document.head.appendChild(link); + // return Promise.resolve(); + + // } else { + // // ESM/JS module loading + // return import(new URL(`${modulePath}.js`, baseUrl).href); + // } + // })); + + // result.then((res) => invokeResult(res[0]), onUnexpectedError); + // ESM-uncomment-end + + // ESM-comment-begin + /** @type {LoaderConfig} */ + const loaderConfig = { + baseUrl: `${fileUriFromPath(configuration.appRoot, { isWindows: safeProcess.platform === 'win32', scheme: 'vscode-file', fallbackAuthority: 'vscode-app' })}/out`, + preferScriptTags: true + }; - // use a trusted types policy when loading via script tags - loaderConfig.trustedTypesPolicy = window.trustedTypes?.createPolicy('amdLoader', { - createScriptURL(value) { - if (value.startsWith(window.location.origin)) { - return value; - } - throw new Error(`Invalid script url: ${value}`); + // use a trusted types policy when loading via script tags + loaderConfig.trustedTypesPolicy = window.trustedTypes?.createPolicy('amdLoader', { + createScriptURL(value) { + if (value.startsWith(window.location.origin)) { + return value; } - }); - - // Teach the loader the location of the node modules we use in renderers - // This will enable to load these modules via + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.esm.html b/src/vs/code/browser/workbench/workbench.esm.html new file mode 100644 index 00000000000..77881982735 --- /dev/null +++ b/src/vs/code/browser/workbench/workbench.esm.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index db7b6475d75..1e2f0459820 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -40,7 +40,10 @@ + diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 8cc2c15e621..e9e78b8ccc4 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -21,6 +21,10 @@ import type { IWorkbenchConstructionOptions, IWorkspace, IWorkspaceProvider } fr import { AuthenticationSessionInfo } from 'vs/workbench/services/authentication/browser/authenticationService'; import type { IURLCallbackProvider } from 'vs/workbench/services/url/browser/urlService'; import { create } from 'vs/workbench/workbench.web.main'; +// --- Start PWB: proxy port url --- +import { extractLocalHostUriMetaDataForPortMapping, TunnelOptions, TunnelCreationOptions } from 'vs/platform/tunnel/common/tunnel'; +import { transformPort } from './urlPorts'; +// --- End PWB --- interface ISecretStorageCrypto { seal(data: string): Promise; @@ -566,11 +570,12 @@ function readCookie(name: string): string | undefined { // Find config by checking for DOM const configElement = mainWindow.document.getElementById('vscode-workbench-web-configuration'); const configElementAttribute = configElement ? configElement.getAttribute('data-settings') : undefined; - if (!configElement || !configElementAttribute) { throw new Error('Missing web configuration element'); } - const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents; workspaceUri?: UriComponents; callbackRoute: string } = JSON.parse(configElementAttribute); + // --- Start PWB --- + const config: IWorkbenchConstructionOptions & { folderUri?: UriComponents; workspaceUri?: UriComponents; callbackRoute: string } = { ...JSON.parse(configElementAttribute), remoteAuthority: location.host }; + // --- End PWB --- const secretStorageKeyPath = readCookie('vscode-secret-key-path'); const secretStorageCrypto = secretStorageKeyPath && ServerKeyedAESCrypto.supported() ? new ServerKeyedAESCrypto(secretStorageKeyPath) : new TransparentCrypto(); @@ -582,6 +587,58 @@ function readCookie(name: string): string | undefined { settingsSyncOptions: config.settingsSyncOptions ? { enabled: config.settingsSyncOptions.enabled, } : undefined, workspaceProvider: WorkspaceProvider.create(config), urlCallbackProvider: new LocalStorageURLCallbackProvider(config.callbackRoute), + // --- PWB Start: proxy port url --- + resolveExternalUri: (uri: URI): Promise => { + let resolvedUri = uri; + const localhostMatch = extractLocalHostUriMetaDataForPortMapping(resolvedUri); + if (localhostMatch && resolvedUri.authority !== location.host) { + if (config.productConfiguration && config.productConfiguration.proxyEndpointTemplate) { + let template = config.productConfiguration.proxyEndpointTemplate; + + // The proxyEndpointTemplate contains the port token after the last slash. + // We extract the port token and remove it from the template. + const portToken = template.split('/').pop(); + template = template.slice(0, template.lastIndexOf('/') + 1); + + let securePort, renderedTemplate; + if (portToken !== undefined) { + securePort = transformPort(portToken, localhostMatch.port); + if (securePort) { + renderedTemplate = template.replace('{{port}}', securePort); + } + } + if (!renderedTemplate) { + // Fallback to /proxy/{{port}}/ when port token is not available. This only occurs when running + // outside of Workbench and is useful for testing. + renderedTemplate = template + .replace('/p/', '/proxy/') + .replace('{{port}}', localhostMatch.port.toString()); + } + resolvedUri = URI.parse(new URL(renderedTemplate, mainWindow.location.href).toString()); + } else { + throw new Error(`Failed to resolve external URI: ${uri.toString()}. Could not determine base url because productConfiguration missing.`); + } + } + return Promise.resolve(resolvedUri); + }, + tunnelProvider: { + tunnelFactory: (tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions) => { + const onDidDispose: Emitter = new Emitter(); + let isDisposed = false; + return Promise.resolve({ + remoteAddress: tunnelOptions.remoteAddress, + localAddress: `localhost:${tunnelOptions.remoteAddress.port}`, + onDidDispose: onDidDispose.event, + dispose: () => { + if (!isDisposed) { + isDisposed = true; + onDidDispose.fire(); + } + } + }); + } + }, + // --- End PWB --- secretStorageProvider: config.remoteAuthority && !secretStorageKeyPath ? undefined /* with a remote without embedder-preferred storage, store on the remote */ : new LocalStorageSecretStorageProvider(secretStorageCrypto), diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 3653fc5b01c..390dd233953 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -121,6 +121,8 @@ import { Lazy } from 'vs/base/common/lazy'; import { IAuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindows'; import { AuxiliaryWindowsMainService } from 'vs/platform/auxiliaryWindow/electron-main/auxiliaryWindowsMainService'; import { normalizeNFC } from 'vs/base/common/normalization'; +import { ICSSDevelopmentService, CSSDevelopmentService } from 'vs/platform/cssDev/node/cssDevService'; + /** * The main VS Code application. There will only ever be one instance, * even if the user starts many instances (e.g. from the command line). @@ -832,34 +834,38 @@ export class CodeApplication extends Disposable { // To: vscode-remote://wsl+ubuntu/mnt/c/GitDevelopment/monaco const secondSlash = uri.path.indexOf(posix.sep, 1 /* skip over the leading slash */); + let authority: string; + let path: string; if (secondSlash !== -1) { - const authority = uri.path.substring(1, secondSlash); - const path = uri.path.substring(secondSlash); - - let query = uri.query; - const params = new URLSearchParams(uri.query); - if (params.get('windowId') === '_blank') { - // Make sure to unset any `windowId=_blank` here - // https://github.com/microsoft/vscode/issues/191902 - params.delete('windowId'); - query = params.toString(); - } + authority = uri.path.substring(1, secondSlash); + path = uri.path.substring(secondSlash); + } else { + authority = uri.path.substring(1); + path = '/'; + } - const remoteUri = URI.from({ scheme: Schemas.vscodeRemote, authority, path, query, fragment: uri.fragment }); + let query = uri.query; + const params = new URLSearchParams(uri.query); + if (params.get('windowId') === '_blank') { + // Make sure to unset any `windowId=_blank` here + // https://github.com/microsoft/vscode/issues/191902 + params.delete('windowId'); + query = params.toString(); + } - if (hasWorkspaceFileExtension(path)) { - return { workspaceUri: remoteUri }; - } + const remoteUri = URI.from({ scheme: Schemas.vscodeRemote, authority, path, query, fragment: uri.fragment }); - if (/:[\d]+$/.test(path)) { - // path with :line:column syntax - return { fileUri: remoteUri }; - } + if (hasWorkspaceFileExtension(path)) { + return { workspaceUri: remoteUri }; + } - return { folderUri: remoteUri }; + if (/:[\d]+$/.test(path)) { + // path with :line:column syntax + return { fileUri: remoteUri }; } - } + return { folderUri: remoteUri }; + } return undefined; } @@ -917,7 +923,7 @@ export class CodeApplication extends Disposable { this.logService.trace('app#handleProtocolUrl() opening protocol url as window:', windowOpenableFromProtocolUrl, uri.toString(true)); const window = firstOrDefault(await windowsMainService.open({ - context: OpenContext.API, + context: OpenContext.LINK, cli: { ...this.environmentMainService.args }, urisToOpen: [windowOpenableFromProtocolUrl], forceNewWindow: shouldOpenInNewWindow, @@ -936,7 +942,7 @@ export class CodeApplication extends Disposable { this.logService.trace('app#handleProtocolUrl() opening empty window and passing in protocol url:', uri.toString(true)); const window = firstOrDefault(await windowsMainService.open({ - context: OpenContext.API, + context: OpenContext.LINK, cli: { ...this.environmentMainService.args }, forceNewWindow: true, forceEmpty: true, @@ -1103,6 +1109,9 @@ export class CodeApplication extends Disposable { // Proxy Auth services.set(IProxyAuthService, new SyncDescriptor(ProxyAuthService)); + // Dev Only: CSS service (for ESM) + services.set(ICSSDevelopmentService, new SyncDescriptor(CSSDevelopmentService, undefined, true)); + // Init services that require it await Promises.settled([ backupMainService.initialize(), diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html new file mode 100644 index 00000000000..19d194fc1c5 --- /dev/null +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.esm.html @@ -0,0 +1,42 @@ + + + + + + + + + +
+ + + + + + diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html index 55f2c0fe81c..5bdf62c8230 100644 --- a/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer-dev.html @@ -35,8 +35,6 @@ - - - + diff --git a/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html b/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html new file mode 100644 index 00000000000..d2747202950 --- /dev/null +++ b/src/vs/code/electron-sandbox/processExplorer/processExplorer.esm.html @@ -0,0 +1,42 @@ + + + + + + + + + + +
+ + + + + diff --git a/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html b/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html new file mode 100644 index 00000000000..ea5cbee848a --- /dev/null +++ b/src/vs/code/electron-sandbox/workbench/workbench-dev.esm.html @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + diff --git a/src/vs/code/electron-sandbox/workbench/workbench-dev.html b/src/vs/code/electron-sandbox/workbench/workbench-dev.html index fa67acf2a97..c9756bf3708 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench-dev.html +++ b/src/vs/code/electron-sandbox/workbench/workbench-dev.html @@ -70,8 +70,7 @@ - - + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.esm.html b/src/vs/code/electron-sandbox/workbench/workbench.esm.html new file mode 100644 index 00000000000..1e89448e605 --- /dev/null +++ b/src/vs/code/electron-sandbox/workbench/workbench.esm.html @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + diff --git a/src/vs/code/electron-sandbox/workbench/workbench.js b/src/vs/code/electron-sandbox/workbench/workbench.js index 5ad97839d23..bed16c9f9bd 100644 --- a/src/vs/code/electron-sandbox/workbench/workbench.js +++ b/src/vs/code/electron-sandbox/workbench/workbench.js @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -/// - //@ts-check 'use strict'; diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 9acf37f930f..58e39456485 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -117,8 +117,7 @@ export async function main(argv: string[]): Promise { // Extensions Management else if (shouldSpawnCliProcess(args)) { - - const cli = await import('vs/code/node/cliProcessMain'); + const cli = await import(['vs', 'code', 'node', 'cliProcessMain'].join('/') /* TODO@esm workaround to prevent esbuild from inlining this */); await cli.main(args); return; @@ -398,7 +397,10 @@ export async function main(argv: string[]): Promise { return false; } if (target.type === 'page') { - return target.url.indexOf('workbench/workbench.html') > 0 || target.url.indexOf('workbench/workbench-dev.html') > 0; + return target.url.indexOf('workbench/workbench.html') > 0 || + target.url.indexOf('workbench/workbench-dev.html') > 0 || + target.url.indexOf('workbench/workbench.esm.html') > 0 || + target.url.indexOf('workbench/workbench-dev.esm.html') > 0; } else { return true; } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 1f70dce4903..55d58d6eef9 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -24,7 +24,6 @@ import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableEle export interface IPointerHandlerHelper { viewDomNode: HTMLElement; - overflowWidgetsDomNode: HTMLElement | null; linesContentDomNode: HTMLElement; viewLinesDomNode: HTMLElement; @@ -63,8 +62,6 @@ export class MouseHandler extends ViewEventHandler { private lastMouseLeaveTime: number; private _height: number; private _mouseLeaveMonitor: IDisposable | null = null; - private _mouseOnOverflowWidgetsDomNode: boolean = false; - private _mouseOnViewDomNode: boolean = false; constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { super(); @@ -79,7 +76,7 @@ export class MouseHandler extends ViewEventHandler { this.viewController, this.viewHelper, this.mouseTargetFactory, - (e, testEventTarget) => this._createMouseTargetForView(e, testEventTarget), + (e, testEventTarget) => this._createMouseTarget(e, testEventTarget), (e) => this._getMouseColumn(e) )); @@ -91,8 +88,7 @@ export class MouseHandler extends ViewEventHandler { this._register(mouseEvents.onContextMenu(this.viewHelper.viewDomNode, (e) => this._onContextMenu(e, true))); this._register(mouseEvents.onMouseMove(this.viewHelper.viewDomNode, (e) => { - this._mouseOnViewDomNode = true; - this._onMouseMoveOverView(e); + this._onMouseMove(e); // See https://github.com/microsoft/vscode/issues/138789 // When moving the mouse really quickly, the browser sometimes forgets to @@ -105,12 +101,7 @@ export class MouseHandler extends ViewEventHandler { this._mouseLeaveMonitor = dom.addDisposableListener(this.viewHelper.viewDomNode.ownerDocument, 'mousemove', (e) => { if (!this.viewHelper.viewDomNode.contains(e.target as Node | null)) { // went outside the editor! - this._mouseOnViewDomNode = false; - setTimeout(() => { - if (!this._mouseOnOverflowWidgetsDomNode) { - this._onMouseLeave(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode)); - } - }, 0); + this._onMouseLeave(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode)); } }); } @@ -118,32 +109,7 @@ export class MouseHandler extends ViewEventHandler { this._register(mouseEvents.onMouseUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e))); - this._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => { - this._mouseOnViewDomNode = false; - setTimeout(() => { - if (!this._mouseOnOverflowWidgetsDomNode) { - this._onMouseLeave(e); - } - }, 0); - })); - - const overflowWidgetsDomNode = this.viewHelper.overflowWidgetsDomNode; - if (overflowWidgetsDomNode) { - this._register(mouseEvents.onMouseMove(overflowWidgetsDomNode, (e) => { - this._mouseOnOverflowWidgetsDomNode = true; - this._mouseLeaveMonitor?.dispose(); - this._mouseLeaveMonitor = null; - this._onMouseMoveOverOverflowWidgetsDomNode(e); - })); - this._register(mouseEvents.onMouseLeave(overflowWidgetsDomNode, (e) => { - this._mouseOnOverflowWidgetsDomNode = false; - setTimeout(() => { - if (!this._mouseOnViewDomNode) { - this._onMouseLeave(e); - } - }, 0); - })); - } + this._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e))); // `pointerdown` events can't be used to determine if there's a double click, or triple click // because their `e.detail` is always 0. @@ -268,10 +234,10 @@ export class MouseHandler extends ViewEventHandler { } const relativePos = createCoordinatesRelativeToEditor(this.viewHelper.viewDomNode, editorPos, pos); - return this.mouseTargetFactory.createMouseTargetForView(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null); + return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null); } - protected _createMouseTargetForView(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget { + protected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget { let target = e.target; if (!this.viewHelper.viewDomNode.contains(target)) { const shadowRoot = dom.getShadowRoot(this.viewHelper.viewDomNode); @@ -281,11 +247,7 @@ export class MouseHandler extends ViewEventHandler { ); } } - return this.mouseTargetFactory.createMouseTargetForView(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null); - } - - private _createMouseTargetForOverflowWidgetsDomNode(e: EditorMouseEvent): IMouseTarget { - return this.mouseTargetFactory.createMouseTargetForOverflowWidgetsDomNode(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, e.target); + return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null); } private _getMouseColumn(e: EditorMouseEvent): number { @@ -295,30 +257,11 @@ export class MouseHandler extends ViewEventHandler { protected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void { this.viewController.emitContextMenu({ event: e, - target: this._createMouseTargetForView(e, testEventTarget) - }); - } - - protected _onMouseMoveOverView(e: EditorMouseEvent): void { - this._onMouseMove(e, this._createMouseTargetForView(e, true)); - } - - private _onMouseMoveOverOverflowWidgetsDomNode(e: EditorMouseEvent): void { - this._onMouseMove(e, this._createMouseTargetForOverflowWidgetsDomNode(e)); - } - - private _onMouseMove(e: EditorMouseEvent, target: IMouseTarget): void { - const shouldIgnoreMouseMoveEvent = this._shouldIgnoreMouseMoveEvent(e); - if (shouldIgnoreMouseMoveEvent) { - return undefined; - } - this.viewController.emitMouseMove({ - event: e, - target + target: this._createMouseTarget(e, testEventTarget) }); } - private _shouldIgnoreMouseMoveEvent(e: EditorMouseEvent): boolean { + protected _onMouseMove(e: EditorMouseEvent): void { const targetIsWidget = this.mouseTargetFactory.mouseTargetIsWidget(e); if (!targetIsWidget) { e.preventDefault(); @@ -326,14 +269,18 @@ export class MouseHandler extends ViewEventHandler { if (this._mouseDownOperation.isActive()) { // In selection/drag operation - return true; + return; } const actualMouseMoveTime = e.timestamp; if (actualMouseMoveTime < this.lastMouseLeaveTime) { // Due to throttling, this event occurred before the mouse left the editor, therefore ignore it. - return true; + return; } - return false; + + this.viewController.emitMouseMove({ + event: e, + target: this._createMouseTarget(e, true) + }); } protected _onMouseLeave(e: EditorMouseEvent): void { @@ -351,12 +298,12 @@ export class MouseHandler extends ViewEventHandler { protected _onMouseUp(e: EditorMouseEvent): void { this.viewController.emitMouseUp({ event: e, - target: this._createMouseTargetForView(e, true) + target: this._createMouseTarget(e, true) }); } protected _onMouseDown(e: EditorMouseEvent, pointerId: number): void { - const t = this._createMouseTargetForView(e, true); + const t = this._createMouseTarget(e, true); const targetIsContent = (t.type === MouseTargetType.CONTENT_TEXT || t.type === MouseTargetType.CONTENT_EMPTY); const targetIsGutter = (t.type === MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === MouseTargetType.GUTTER_LINE_NUMBERS || t.type === MouseTargetType.GUTTER_LINE_DECORATIONS); @@ -795,7 +742,7 @@ class TopBottomDragScrollingOperation extends Disposable { const horizontalScrollbarHeight = this._context.configuration.options.get(EditorOption.layoutInfo).horizontalScrollbarHeight; const pos = new PageCoordinates(this._mouseEvent.pos.x, editorPos.y + editorPos.height - horizontalScrollbarHeight - 0.1); const relativePos = createCoordinatesRelativeToEditor(this._viewHelper.viewDomNode, editorPos, pos); - mouseTarget = this._mouseTargetFactory.createMouseTargetForView(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null); + mouseTarget = this._mouseTargetFactory.createMouseTarget(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null); } if (!mouseTarget.position || mouseTarget.position.lineNumber !== edgeLineNumber) { if (this._position.outsidePosition === 'above') { diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index c0f66317e9a..4a1addb3fc0 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -238,7 +238,6 @@ export class HitTestContext { public readonly viewModel: IViewModel; public readonly layoutInfo: EditorLayoutInfo; public readonly viewDomNode: HTMLElement; - public readonly overflowWidgetsDomNode: HTMLElement | null; public readonly lineHeight: number; public readonly stickyTabStops: boolean; public readonly typicalHalfwidthCharacterWidth: number; @@ -252,7 +251,6 @@ export class HitTestContext { const options = context.configuration.options; this.layoutInfo = options.get(EditorOption.layoutInfo); this.viewDomNode = viewHelper.viewDomNode; - this.overflowWidgetsDomNode = viewHelper.overflowWidgetsDomNode ?? null; this.lineHeight = options.get(EditorOption.lineHeight); this.stickyTabStops = options.get(EditorOption.stickyTabStops); this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth; @@ -415,7 +413,6 @@ class HitTestRequest extends BareHitTestRequest { private _useHitTestTarget: boolean; private _targetPathCacheElement: HTMLElement | null = null; private _targetPathCacheValue: Uint8Array = new Uint8Array(0); - private _targetElement: HTMLElement | null = null; public get target(): HTMLElement | null { if (this._useHitTestTarget) { @@ -425,18 +422,17 @@ class HitTestRequest extends BareHitTestRequest { } public get targetPath(): Uint8Array { - if (this._targetPathCacheElement !== this.target && this._targetElement) { + if (this._targetPathCacheElement !== this.target) { this._targetPathCacheElement = this.target; - this._targetPathCacheValue = PartFingerprints.collect(this.target, this._targetElement); + this._targetPathCacheValue = PartFingerprints.collect(this.target, this._ctx.viewDomNode); } return this._targetPathCacheValue; } - constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, eventTarget: HTMLElement | null, targetElement: HTMLElement | null = null) { + constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, eventTarget: HTMLElement | null) { super(ctx, editorPos, pos, relativePos); this._ctx = ctx; this._eventTarget = eventTarget; - this._targetElement = targetElement; // If no event target is passed in, we will use the hit test target const hasEventTarget = Boolean(this._eventTarget); @@ -536,9 +532,9 @@ export class MouseTargetFactory { return false; } - public createMouseTargetForView(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget { + public createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget { const ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData); - const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target, ctx.viewDomNode); + const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target); try { const r = MouseTargetFactory._createMouseTarget(ctx, request); @@ -559,16 +555,6 @@ export class MouseTargetFactory { } } - public createMouseTargetForOverflowWidgetsDomNode(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null) { - const ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData); - const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target, ctx.overflowWidgetsDomNode); - try { - return MouseTargetFactory._createMouseTarget(ctx, request); - } catch (err) { - return request.fulfillUnknown(); - } - } - private static _createMouseTarget(ctx: HitTestContext, request: HitTestRequest): IMouseTarget { // console.log(`${domHitTestExecuted ? '=>' : ''}CAME IN REQUEST: ${request}`); diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index 258884eafa8..2019016ac4c 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -47,7 +47,7 @@ export class PointerEventHandler extends MouseHandler { // PonterEvents const pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode); - this._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMoveOverView(e))); + this._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMove(e))); this._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e))); this._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e))); this._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e, pointerId) => this._onMouseDown(e, pointerId))); @@ -73,7 +73,7 @@ export class PointerEventHandler extends MouseHandler { } private _dispatchGesture(event: GestureEvent, inSelectionMode: boolean): void { - const target = this._createMouseTargetForView(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); + const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); if (target.position) { this.viewController.dispatchMouse({ position: target.position, @@ -119,7 +119,7 @@ class TouchHandler extends MouseHandler { this.viewHelper.focusTextArea(); - const target = this._createMouseTargetForView(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); + const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false); if (target.position) { // Send the tap event also to the